From 0b7efee707744fc1cd489b122f7f70f2a8adf237 Mon Sep 17 00:00:00 2001 From: guanbinrui Date: Mon, 28 Mar 2022 17:47:50 +0800 Subject: [PATCH 01/42] chore: bump version to 2.6.1 --- package.json | 2 +- packages/mask/src/manifest.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 45489dd935e6..974cdb360adf 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ "yarn": ">=999.0.0", "npm": ">=999.0.0" }, - "version": "2.6.0", + "version": "2.6.1", "private": true, "license": "AGPL-3.0-or-later", "scripts": { diff --git a/packages/mask/src/manifest.json b/packages/mask/src/manifest.json index f436056eeecf..e1ca0e475f5f 100644 --- a/packages/mask/src/manifest.json +++ b/packages/mask/src/manifest.json @@ -1,6 +1,6 @@ { "name": "Mask Network", - "version": "2.6.0", + "version": "2.6.1", "manifest_version": 2, "permissions": ["storage", "downloads", "webNavigation", "activeTab"], "optional_permissions": ["", "notifications", "clipboardRead"], From deccad2b98755944f6b11200b3f4623ca326a990 Mon Sep 17 00:00:00 2001 From: UncleBill Date: Tue, 29 Mar 2022 12:39:02 +0800 Subject: [PATCH 02/42] fix(tip): styling tip button in post (#5981) * fix(tip): styling tip button in post * fixup! fix(tip): styling tip button in post --- .../NextID/components/Tip/TipButton.tsx | 44 ++++++++++++++++--- 1 file changed, 38 insertions(+), 6 deletions(-) diff --git a/packages/mask/src/plugins/NextID/components/Tip/TipButton.tsx b/packages/mask/src/plugins/NextID/components/Tip/TipButton.tsx index aaaad373542e..587c4c52f96b 100644 --- a/packages/mask/src/plugins/NextID/components/Tip/TipButton.tsx +++ b/packages/mask/src/plugins/NextID/components/Tip/TipButton.tsx @@ -4,6 +4,7 @@ import { NextIDPlatform, ProfileIdentifier } from '@masknet/shared-base' import { makeStyles, ShadowRootTooltip } from '@masknet/theme' import { queryExistedBindingByPersona, queryIsBound } from '@masknet/web3-providers' import { EMPTY_LIST } from '@masknet/web3-shared-evm' +import type { TooltipProps } from '@mui/material' import classnames from 'classnames' import { uniq } from 'lodash-unified' import { FC, HTMLProps, MouseEventHandler, useCallback, useMemo } from 'react' @@ -16,6 +17,7 @@ import { PluginNextIdMessages } from '../../messages' interface Props extends HTMLProps { addresses?: string[] receiver?: ProfileIdentifier + tooltipProps?: Partial } const useStyles = makeStyles()({ @@ -26,20 +28,41 @@ const useStyles = makeStyles()({ alignItems: 'center', fontFamily: '-apple-system, system-ui, sans-serif', }, - postTipButton: { - display: 'flex', + buttonWrapper: { // temporarily hard code height: 46, + display: 'flex', alignItems: 'center', color: '#8899a6', }, + postTipButton: { + cursor: 'pointer', + width: 34, + height: 34, + borderRadius: '100%', + '&:hover': { + backgroundColor: 'rgba(20,155,240,0.1)', + }, + }, + tooltip: { + backgroundColor: 'rgb(102,102,102)', + color: 'white', + marginTop: '0 !important', + }, disabled: { opacity: 0.4, cursor: 'default', }, }) -export const TipButton: FC = ({ className, receiver, addresses = EMPTY_LIST, children, ...rest }) => { +export const TipButton: FC = ({ + className, + receiver, + addresses = EMPTY_LIST, + children, + tooltipProps, + ...rest +}) => { const { classes } = useStyles() const t = useI18N() @@ -104,15 +127,24 @@ export const TipButton: FC = ({ className, receiver, addresses = EMPTY_LI if (disabled) return ( - + {dom} ) return dom } -export const PostTipButton: FC = (props) => { +export const PostTipButton: FC = ({ className, ...rest }) => { const identifier = usePostInfoDetails.author() const { classes } = useStyles() - return + return ( +
+ +
+ ) } From 037b1bb92158f4af23b37a6bddf1e19da00a5f73 Mon Sep 17 00:00:00 2001 From: guanbinrui <52657989+guanbinrui@users.noreply.github.com> Date: Thu, 31 Mar 2022 16:25:23 +0800 Subject: [PATCH 03/42] fix: twitter nickname selector (#6006) --- .../twitter.com/collecting/identity.ts | 4 ++-- .../social-network-adaptor/twitter.com/utils/selector.ts | 4 ++-- .../src/social-network-adaptor/twitter.com/utils/user.ts | 8 ++++---- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/mask/src/social-network-adaptor/twitter.com/collecting/identity.ts b/packages/mask/src/social-network-adaptor/twitter.com/collecting/identity.ts index 77cab412d085..906d2ce076c3 100644 --- a/packages/mask/src/social-network-adaptor/twitter.com/collecting/identity.ts +++ b/packages/mask/src/social-network-adaptor/twitter.com/collecting/identity.ts @@ -5,7 +5,7 @@ import { ProfileIdentifier } from '@masknet/shared-base' import { creator, SocialNetworkUI as Next } from '../../../social-network' import Services from '../../../extension/service' import { twitterBase } from '../base' -import { getAvatar, getBioDescription, getNickname, getTwitterId, getPersonalHomepage } from '../utils/user' +import { getAvatar, getBio, getNickname, getTwitterId, getPersonalHomepage } from '../utils/user' import { delay } from '@dimensiondev/kit' function resolveLastRecognizedIdentityInner( @@ -43,7 +43,7 @@ function resolveCurrentVisitingIdentityInner( const avatarMetaSelector = searchAvatarMetaSelector() const assign = async () => { await delay(500) - const bio = getBioDescription() + const bio = getBio() const homepage = getPersonalHomepage() const nickname = getNickname() const handle = getTwitterId() diff --git a/packages/mask/src/social-network-adaptor/twitter.com/utils/selector.ts b/packages/mask/src/social-network-adaptor/twitter.com/utils/selector.ts index 398d94890015..fb567de08e29 100644 --- a/packages/mask/src/social-network-adaptor/twitter.com/utils/selector.ts +++ b/packages/mask/src/social-network-adaptor/twitter.com/utils/selector.ts @@ -57,7 +57,7 @@ export const searchNewTweetButtonSelector: () => LiveSelector = () => { } export const searchNickNameSelector: () => LiveSelector = () => - querySelector('[data-testid="tweet"] a:not([target]) > div > div[dir="auto"] > span > span') + querySelector('[data-testid="primaryColumn"] [data-testid="UserName"] div[dir="auto"] > span > span') export const searchAvatarSelector = () => querySelector('[data-testid="primaryColumn"] a[href$="/photo"] img[src*="profile_images"]') export const searchNFTAvatarSelector = () => @@ -146,7 +146,7 @@ export const twitterMainAvatarSelector: () => LiveSelector = () => export const newPostButtonSelector = () => querySelector('[data-testid="SideNav_NewTweet_Button"]') -export const bioDescriptionSelector = () => querySelector('[data-testid="UserDescription"]') +export const profileBioSelector = () => querySelector('[data-testid="UserDescription"]') export const personalHomepageSelector = () => querySelector('[data-testid="UserUrl"]') diff --git a/packages/mask/src/social-network-adaptor/twitter.com/utils/user.ts b/packages/mask/src/social-network-adaptor/twitter.com/utils/user.ts index 1fab6ced45c1..d0f6a1f62a6e 100644 --- a/packages/mask/src/social-network-adaptor/twitter.com/utils/user.ts +++ b/packages/mask/src/social-network-adaptor/twitter.com/utils/user.ts @@ -1,7 +1,7 @@ import { isNull } from 'lodash-unified' import type { SocialNetwork } from '../../../social-network' import { - bioDescriptionSelector, + profileBioSelector, searchAvatarSelector, searchNickNameSelector, personalHomepageSelector, @@ -23,7 +23,7 @@ export const usernameValidator: NonNullable { - const node = searchNickNameSelector().evaluate()?.querySelector('span span') + const node = searchNickNameSelector().evaluate() if (!node) return '' return collectNodeText(node) @@ -42,8 +42,8 @@ export const getTwitterId = () => { return '' } -export const getBioDescription = () => { - const node = bioDescriptionSelector().evaluate() +export const getBio = () => { + const node = profileBioSelector().evaluate() return node ? collectNodeText(node) : '' } From e53b768117c776d82d3fedff2a47b78b45929064 Mon Sep 17 00:00:00 2001 From: UncleBill Date: Wed, 30 Mar 2022 10:27:47 +0800 Subject: [PATCH 04/42] fix(tip): change promote text in share message (#5984) --- .../mask/src/plugins/NextID/components/Tip/TipDialog.tsx | 3 +++ packages/mask/src/plugins/NextID/locales/en-US.json | 5 +++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/mask/src/plugins/NextID/components/Tip/TipDialog.tsx b/packages/mask/src/plugins/NextID/components/Tip/TipDialog.tsx index 0f0a364ce07b..a444087be0fc 100644 --- a/packages/mask/src/plugins/NextID/components/Tip/TipDialog.tsx +++ b/packages/mask/src/plugins/NextID/components/Tip/TipDialog.tsx @@ -88,17 +88,20 @@ export function TipDialog({ open = false, onClose }: TipDialogProps) { const isTokenTip = tipType === TipType.Token const shareLink = useMemo(() => { + const promote = t.tip_mask_promote() const message = isTokenTip ? t.tip_token_share_post({ amount, symbol: token?.symbol || 'token', recipientSnsId, recipient, + promote, }) : t.tip_nft_share_post({ name: erc721Contract?.name || '', recipientSnsId, recipient, + promote, }) return activatedSocialNetworkUI.utils.getShareLinkURL?.(message) }, [amount, isTokenTip, erc721Contract?.name, token, recipient, recipientSnsId, t]) diff --git a/packages/mask/src/plugins/NextID/locales/en-US.json b/packages/mask/src/plugins/NextID/locales/en-US.json index a271b612e0ed..a9b3f95a04e6 100644 --- a/packages/mask/src/plugins/NextID/locales/en-US.json +++ b/packages/mask/src/plugins/NextID/locales/en-US.json @@ -60,6 +60,7 @@ "tip_connect_wallet": "Connect Wallet", "search": "Search", "tip_contracts": "Contracts", - "tip_token_share_post": "I just tipped {{amount}} {{symbol}} to @{{recipientSnsId}}'s wallet address {{recipient}}\n\nInstall https://mask.io/download-links to send my first tip.", - "tip_nft_share_post": "I just tipped a {{name}} to @{{recipientSnsId}}'s wallet address {{recipient}}\n\nInstall https://mask.io/download-links to send my first tip." + "tip_mask_promote": "Install https://mask.io/download-links to send your first tip.", + "tip_token_share_post": "I just tipped {{amount}} {{symbol}} to @{{recipientSnsId}}'s wallet address {{recipient}}\n\n{{promote}}", + "tip_nft_share_post": "I just tipped a {{name}} to @{{recipientSnsId}}'s wallet address {{recipient}}\n\n{{promote}}" } From 825816ceac977e25c059ca1e7c217b2c3a5cf85d Mon Sep 17 00:00:00 2001 From: lelenei <72531217+lelenei@users.noreply.github.com> Date: Wed, 30 Mar 2022 11:09:38 +0800 Subject: [PATCH 05/42] fix: lost default network indicator (#5976) * fix: lost default network indicator * refactor: reply review --- .../plugins/Wallet/SNSAdaptor/SelectProviderDialog/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/index.tsx b/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/index.tsx index a76885ba440c..76b85bb20100 100644 --- a/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/index.tsx +++ b/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/index.tsx @@ -51,7 +51,7 @@ export function SelectProviderDialog(props: SelectProviderDialogProps) { const pluginID = useValueRef(pluginIDSettings) as NetworkPluginID const network = useNetworkDescriptor() const [undeterminedPluginID, setUndeterminedPluginID] = useState(pluginID) - const [undeterminedNetworkID, setUndeterminedNetworkID] = useState(network?.ID) + const [undeterminedNetworkID, setUndeterminedNetworkID] = useState(network?.ID ?? NetworkPluginID.PLUGIN_EVM) const undeterminedNetwork = useNetworkDescriptor(undeterminedNetworkID, undeterminedPluginID) const networkType = useNetworkType(undeterminedPluginID) From 095a7408f9035a8714bc68a7ced9d1c96de8a41f Mon Sep 17 00:00:00 2001 From: UncleBill Date: Mon, 28 Mar 2022 19:07:46 +0800 Subject: [PATCH 06/42] fix(tip): ajust size of tip button according to twitter's (#5970) --- .../twitter.com/injection/Tip/ProfileTipButton.tsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/mask/src/social-network-adaptor/twitter.com/injection/Tip/ProfileTipButton.tsx b/packages/mask/src/social-network-adaptor/twitter.com/injection/Tip/ProfileTipButton.tsx index 2329b7d9ec1d..625e3b3a6297 100644 --- a/packages/mask/src/social-network-adaptor/twitter.com/injection/Tip/ProfileTipButton.tsx +++ b/packages/mask/src/social-network-adaptor/twitter.com/injection/Tip/ProfileTipButton.tsx @@ -17,14 +17,14 @@ export function injectOpenTipButtonOnProfile(signal: AbortSignal) { } interface StyleProps { - minHeight: number + size: number fontSize: number marginBottom: number } const useStyles = makeStyles()((theme, props) => ({ button: { - height: 34, - width: 34, + height: props.size, + width: props.size, display: 'flex', justifyContent: 'center', alignItems: 'center', @@ -47,7 +47,7 @@ const useStyles = makeStyles()((theme, props) => ({ })) function OpenTipDialog() { - const [style, setStyle] = useState({ minHeight: 32, fontSize: 14, marginBottom: 11 }) + const [style, setStyle] = useState({ size: 34, fontSize: 14, marginBottom: 11 }) const visitingPersona = useCurrentVisitingIdentity() const setStyleFromEditProfileSelector = () => { @@ -55,7 +55,7 @@ function OpenTipDialog() { if (!menuButton) return const css = window.getComputedStyle(menuButton) setStyle({ - minHeight: Number.parseFloat(css.minHeight.replace('px', '')), + size: Number.parseFloat(css.height.replace('px', '')), fontSize: Number.parseFloat(css.fontSize.replace('px', '')), marginBottom: Number.parseFloat(css.marginBottom.replace('px', '')), }) From 8a7afefa30c5d00fdbbd1da440653c42cd14a5fc Mon Sep 17 00:00:00 2001 From: Hancheng Zhou Date: Wed, 30 Mar 2022 18:09:37 +0800 Subject: [PATCH 07/42] fix: lucky drop send from past use image payload (#5992) --- .../RedPacket/SNSAdaptor/RedPacketInHistoryList.tsx | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/packages/mask/src/plugins/RedPacket/SNSAdaptor/RedPacketInHistoryList.tsx b/packages/mask/src/plugins/RedPacket/SNSAdaptor/RedPacketInHistoryList.tsx index 73fe3c6ce61e..3a5495fe28ca 100644 --- a/packages/mask/src/plugins/RedPacket/SNSAdaptor/RedPacketInHistoryList.tsx +++ b/packages/mask/src/plugins/RedPacket/SNSAdaptor/RedPacketInHistoryList.tsx @@ -4,6 +4,7 @@ import classNames from 'classnames' import { Box, ListItem, Typography, Popper, useMediaQuery, Theme } from '@mui/material' import { makeStyles } from '@masknet/theme' import { Trans } from 'react-i18next' +import { omit } from 'lodash-unified' import { RedPacketJSONPayload, RedPacketStatus, RedPacketJSONPayloadFromChain } from '../types' import { TokenIcon } from '@masknet/shared' import { useRemoteControlledDialog } from '@masknet/shared-base-ui' @@ -14,6 +15,7 @@ import { useAccount, isSameAddress, EthereumTokenType, + FungibleTokenDetailed, useFungibleTokenDetailed, useTokenConstants, } from '@masknet/web3-shared-evm' @@ -236,7 +238,7 @@ export function RedPacketInHistoryList(props: RedPacketInHistoryListProps) { const onSendOrRefund = useCallback(async () => { if (canRefund) await refundCallback() - if (canSend) onSelect({ ...history, token: historyToken }) + if (canSend) onSelect(removeUselessSendParams({ ...history, token: historyToken as FungibleTokenDetailed })) }, [onSelect, refundCallback, canRefund, canSend, history]) // #region password lost tips @@ -379,3 +381,10 @@ export function RedPacketInHistoryList(props: RedPacketInHistoryListProps) { ) } + +function removeUselessSendParams(payload: RedPacketJSONPayload): RedPacketJSONPayload { + return { + ...omit(payload, ['block_number', 'claimers']), + token: omit(payload.token, ['logoURI']) as FungibleTokenDetailed, + } +} From 214ae8f775c92730e071e5332b7b58c0fc807839 Mon Sep 17 00:00:00 2001 From: Hancheng Zhou Date: Wed, 30 Mar 2022 18:09:01 +0800 Subject: [PATCH 08/42] fix: web3 tab lose focus (#5988) * chore: path * fix: url change proxy * chore: add comment * chore: little fix --- packages/injected-script/main/locationChange.ts | 13 +++++++++++-- .../components/InjectedComponents/ProfileTab.tsx | 5 +++-- .../InjectedComponents/ProfileTabContent.tsx | 3 +-- .../injection/NFT/NFTAvatarEditProfile.tsx | 3 +-- .../injection/NFT/ProfileNFTAvatar.tsx | 3 +-- .../injection/NFT/NFTAvatarEditProfile.tsx | 3 +-- .../twitter.com/injection/Tip/ProfileTipButton.tsx | 3 +-- packages/mask/src/utils/hooks/index.ts | 1 + 8 files changed, 20 insertions(+), 14 deletions(-) diff --git a/packages/injected-script/main/locationChange.ts b/packages/injected-script/main/locationChange.ts index 4f1e05d0b8bd..26ed22e27521 100644 --- a/packages/injected-script/main/locationChange.ts +++ b/packages/injected-script/main/locationChange.ts @@ -1,12 +1,16 @@ import { apply, dispatchEvent, no_xray_Event, no_xray_Proxy } from './intrinsic' function setupChromium() { + let currentLocationHref = window.location.href // Learn more about this hack from https://stackoverflow.com/a/52809105/1986338 window.history.pushState = new no_xray_Proxy(history.pushState, { apply(target, thisArg, params: any) { const val = apply(target, thisArg, params) apply(dispatchEvent, window, [new no_xray_Event('pushstate')]) - apply(dispatchEvent, window, [new no_xray_Event('locationchange')]) + if (currentLocationHref !== window.location.href) { + currentLocationHref = window.location.href + apply(dispatchEvent, window, [new no_xray_Event('locationchange')]) + } return val }, }) @@ -14,12 +18,17 @@ function setupChromium() { apply(target, thisArg, params: any) { const val = apply(target, thisArg, params) apply(dispatchEvent, window, [new no_xray_Event('replacestate')]) - apply(dispatchEvent, window, [new no_xray_Event('locationchange')]) + if (currentLocationHref !== window.location.href) { + currentLocationHref = window.location.href + apply(dispatchEvent, window, [new no_xray_Event('locationchange')]) + } return val }, }) window.addEventListener('popstate', () => { + if (currentLocationHref === window.location.href) return + currentLocationHref = window.location.href apply(dispatchEvent, window, [new no_xray_Event('locationchange')]) }) } diff --git a/packages/mask/src/components/InjectedComponents/ProfileTab.tsx b/packages/mask/src/components/InjectedComponents/ProfileTab.tsx index 5fd1d7fe5acb..8a45f7620a25 100644 --- a/packages/mask/src/components/InjectedComponents/ProfileTab.tsx +++ b/packages/mask/src/components/InjectedComponents/ProfileTab.tsx @@ -1,8 +1,7 @@ import { ReactElement, useCallback, useState } from 'react' import classnames from 'classnames' import { Typography } from '@mui/material' -import { MaskMessages, useMatchXS } from '../../utils' -import { useLocationChange } from '../../utils/hooks/useLocationChange' +import { MaskMessages, useMatchXS, useLocationChange } from '../../utils' export interface ProfileTabProps extends withClasses<'tab' | 'button' | 'selected'> { clear(): void @@ -20,6 +19,8 @@ export function ProfileTab(props: ProfileTabProps) { const isMobile = useMatchXS() const onClick = useCallback(() => { + // Change the url hashtag to trigger `locationchange` event from e.g. 'hostname/medias#web3 => hostname/medias' + location.assign('#web3') MaskMessages.events.profileTabUpdated.sendToLocal({ show: true }) setActive(true) clear() diff --git a/packages/mask/src/components/InjectedComponents/ProfileTabContent.tsx b/packages/mask/src/components/InjectedComponents/ProfileTabContent.tsx index ed54e332a37f..c54ef4ea9e50 100644 --- a/packages/mask/src/components/InjectedComponents/ProfileTabContent.tsx +++ b/packages/mask/src/components/InjectedComponents/ProfileTabContent.tsx @@ -7,8 +7,7 @@ import { makeStyles, useStylesExtends } from '@masknet/theme' import { useAddressNames } from '@masknet/web3-shared-evm' import { createInjectHooksRenderer, useActivatedPluginsSNSAdaptor, Plugin, PluginId } from '@masknet/plugin-infra' import { PageTab } from '../InjectedComponents/PageTab' -import { useLocationChange } from '../../utils/hooks/useLocationChange' -import { MaskMessages, useI18N } from '../../utils' +import { MaskMessages, useI18N, useLocationChange } from '../../utils' import { useCurrentVisitingIdentity, useLastRecognizedIdentity } from '../DataSource/useActivatedUI' import { useNextIDBoundByPlatform } from '../DataSource/useNextID' import { usePersonaConnectStatus } from '../DataSource/usePersonaConnectStatus' diff --git a/packages/mask/src/social-network-adaptor/facebook.com/injection/NFT/NFTAvatarEditProfile.tsx b/packages/mask/src/social-network-adaptor/facebook.com/injection/NFT/NFTAvatarEditProfile.tsx index 1280efe19771..fc0caf2bf5c7 100644 --- a/packages/mask/src/social-network-adaptor/facebook.com/injection/NFT/NFTAvatarEditProfile.tsx +++ b/packages/mask/src/social-network-adaptor/facebook.com/injection/NFT/NFTAvatarEditProfile.tsx @@ -1,8 +1,7 @@ import { MutationObserverWatcher } from '@dimensiondev/holoflows-kit' import { searchFacebookEditProfileSelector, searchFacebookProfileSettingButtonSelector } from '../../utils/selector' -import { createReactRootShadowed, startWatch } from '../../../../utils' +import { createReactRootShadowed, startWatch, useLocationChange } from '../../../../utils' import { useLayoutEffect, useState } from 'react' -import { useLocationChange } from '../../../../utils/hooks/useLocationChange' import { NFTAvatarButton } from '../../../../plugins/Avatar/SNSAdaptor/NFTAvatarButton' import { makeStyles } from '@masknet/theme' diff --git a/packages/mask/src/social-network-adaptor/instagram.com/injection/NFT/ProfileNFTAvatar.tsx b/packages/mask/src/social-network-adaptor/instagram.com/injection/NFT/ProfileNFTAvatar.tsx index 5956adb2f5c8..4b3fd6fc0e95 100644 --- a/packages/mask/src/social-network-adaptor/instagram.com/injection/NFT/ProfileNFTAvatar.tsx +++ b/packages/mask/src/social-network-adaptor/instagram.com/injection/NFT/ProfileNFTAvatar.tsx @@ -1,9 +1,8 @@ import { MutationObserverWatcher } from '@dimensiondev/holoflows-kit' import { searchInstagramAvatarListSelector } from '../../utils/selector' -import { createReactRootShadowed, MaskMessages, startWatch, useI18N } from '../../../../utils' +import { createReactRootShadowed, MaskMessages, startWatch, useI18N, useLocationChange } from '../../../../utils' import { makeStyles } from '@masknet/theme' import { useCallback, useLayoutEffect, useState } from 'react' -import { useLocationChange } from '../../../../utils/hooks/useLocationChange' import { useLocation } from 'react-use' export async function injectProfileNFTAvatarInInstagram(signal: AbortSignal) { diff --git a/packages/mask/src/social-network-adaptor/twitter.com/injection/NFT/NFTAvatarEditProfile.tsx b/packages/mask/src/social-network-adaptor/twitter.com/injection/NFT/NFTAvatarEditProfile.tsx index 086e8df6b830..6f701edbf04b 100644 --- a/packages/mask/src/social-network-adaptor/twitter.com/injection/NFT/NFTAvatarEditProfile.tsx +++ b/packages/mask/src/social-network-adaptor/twitter.com/injection/NFT/NFTAvatarEditProfile.tsx @@ -2,8 +2,7 @@ import { MutationObserverWatcher } from '@dimensiondev/holoflows-kit' import { makeStyles } from '@masknet/theme' import { useState, useEffect } from 'react' import { NFTAvatarButton } from '../../../../plugins/Avatar/SNSAdaptor/NFTAvatarButton' -import { startWatch, createReactRootShadowed } from '../../../../utils' -import { useLocationChange } from '../../../../utils/hooks/useLocationChange' +import { startWatch, createReactRootShadowed, useLocationChange } from '../../../../utils' import { searchEditProfileSelector } from '../../utils/selector' export function injectOpenNFTAvatarEditProfileButton(signal: AbortSignal) { diff --git a/packages/mask/src/social-network-adaptor/twitter.com/injection/Tip/ProfileTipButton.tsx b/packages/mask/src/social-network-adaptor/twitter.com/injection/Tip/ProfileTipButton.tsx index 625e3b3a6297..b23b444d28a9 100644 --- a/packages/mask/src/social-network-adaptor/twitter.com/injection/Tip/ProfileTipButton.tsx +++ b/packages/mask/src/social-network-adaptor/twitter.com/injection/Tip/ProfileTipButton.tsx @@ -3,8 +3,7 @@ import { makeStyles } from '@masknet/theme' import { useEffect, useState } from 'react' import { useCurrentVisitingIdentity } from '../../../../components/DataSource/useActivatedUI' import { TipButton } from '../../../../plugins/NextID/components/Tip/TipButton' -import { createReactRootShadowed, startWatch } from '../../../../utils' -import { useLocationChange } from '../../../../utils/hooks/useLocationChange' +import { createReactRootShadowed, startWatch, useLocationChange } from '../../../../utils' import { profileFollowButtonSelector as selector, profileMenuButtonSelector as menuButtonSelector, diff --git a/packages/mask/src/utils/hooks/index.ts b/packages/mask/src/utils/hooks/index.ts index 5d302e13ece0..924c4887e5d5 100644 --- a/packages/mask/src/utils/hooks/index.ts +++ b/packages/mask/src/utils/hooks/index.ts @@ -4,3 +4,4 @@ export * from './useMenu' export * from './useQueryNavigatorPermission' export * from './useSettingSwitcher' export * from './useSuspense' +export * from './useLocationChange' From 24bf21ce9d17657769fda9dc77505cf7fd326ae8 Mon Sep 17 00:00:00 2001 From: Jack Works Date: Sat, 26 Mar 2022 18:23:48 +0800 Subject: [PATCH 09/42] chore: add cross isolation message (#5961) --- packages/shared-base/src/Messages/Shared.ts | 17 +++++++++++++++++ packages/shared-base/src/index.ts | 1 + 2 files changed, 18 insertions(+) create mode 100644 packages/shared-base/src/Messages/Shared.ts diff --git a/packages/shared-base/src/Messages/Shared.ts b/packages/shared-base/src/Messages/Shared.ts new file mode 100644 index 000000000000..1bc24f53efe0 --- /dev/null +++ b/packages/shared-base/src/Messages/Shared.ts @@ -0,0 +1,17 @@ +import { WebExtensionMessage } from '@dimensiondev/holoflows-kit' + +/** + * @deprecated + * Prefer MaskMessages. + * + * Only use this in the following cases: + * + * - You need to send message across different plugins + * e.g. from the packages/plugins/Example to packages/plugins/Example2 + * - You need to send message from plugin + * e.g. packages/plugins/Example to the main Mask extension. + */ +// TODO: find a way to use a good API for cross isolation communication. +export const CrossIsolationMessages = new WebExtensionMessage({ domain: '_' }) + +export interface CrossIsolationEvents {} diff --git a/packages/shared-base/src/index.ts b/packages/shared-base/src/index.ts index ec82b1b74743..56e35ef4537e 100644 --- a/packages/shared-base/src/index.ts +++ b/packages/shared-base/src/index.ts @@ -13,6 +13,7 @@ export * from './Persona/type' export * from './Site/type' export * from './Routes' export * from './Messages/Mask' +export * from './Messages/Shared' export * from './Results' export * from './convert' export * from './NextID/type' From 8091440ecf8aed94c71a250ea2c004fc8f9f044d Mon Sep 17 00:00:00 2001 From: Hancheng Zhou Date: Mon, 28 Mar 2022 17:01:02 +0800 Subject: [PATCH 10/42] refactor: shared message bus (#5971) --- .../mask/src/components/CompositionDialog/Composition.tsx | 3 ++- packages/mask/src/components/shared/ApplicationBoard.tsx | 4 ++-- .../plugins/Wallet/SNSAdaptor/WalletStatusDialog/index.tsx | 4 ++-- .../facebook.com/automation/openComposeBox.ts | 4 ++-- .../facebook.com/injection/Composition.tsx | 6 +++--- .../instagram.com/injection/Entry.tsx | 4 ++-- .../minds.com/automation/openComposeBox.ts | 4 ++-- .../minds.com/injection/PostDialogHint.tsx | 4 ++-- .../twitter.com/automation/openComposeBox.ts | 4 ++-- .../twitter.com/injection/PostDialogHint.tsx | 4 ++-- packages/shared-base/src/Messages/Shared.ts | 5 ++++- 11 files changed, 25 insertions(+), 21 deletions(-) diff --git a/packages/mask/src/components/CompositionDialog/Composition.tsx b/packages/mask/src/components/CompositionDialog/Composition.tsx index cd5a11b5b22c..99bb69510111 100644 --- a/packages/mask/src/components/CompositionDialog/Composition.tsx +++ b/packages/mask/src/components/CompositionDialog/Composition.tsx @@ -3,6 +3,7 @@ import { DialogContent } from '@mui/material' import { DialogStackingProvider } from '@masknet/theme' import { activatedSocialNetworkUI, globalUIState } from '../../social-network' import { MaskMessages, useI18N } from '../../utils' +import { CrossIsolationMessages } from '@masknet/shared-base' import { useFriendsList as useRecipientsList } from '../DataSource/useActivatedUI' import { InjectedDialog } from '../shared/InjectedDialog' import { CompositionDialogUI, CompositionRef } from './CompositionUI' @@ -45,7 +46,7 @@ export function Composition({ type = 'timeline', requireClipboardPermission }: P }, [onQueryClipboardPermission]) useEffect(() => { - return MaskMessages.events.requestComposition.on(({ reason, open, content, options }) => { + return CrossIsolationMessages.events.requestComposition.on(({ reason, open, content, options }) => { if ( (reason !== 'reply' && reason !== type) || (reason === 'reply' && type === 'popup') || diff --git a/packages/mask/src/components/shared/ApplicationBoard.tsx b/packages/mask/src/components/shared/ApplicationBoard.tsx index 6df629f5fb51..5980a8b9cfb8 100644 --- a/packages/mask/src/components/shared/ApplicationBoard.tsx +++ b/packages/mask/src/components/shared/ApplicationBoard.tsx @@ -4,7 +4,7 @@ import { Typography } from '@mui/material' import { makeStyles } from '@masknet/theme' import { ChainId, useChainId, useAccount, useWallet } from '@masknet/web3-shared-evm' import { useRemoteControlledDialog } from '@masknet/shared-base-ui' -import { MaskMessages } from '../../utils/messages' +import { CrossIsolationMessages } from '@masknet/shared-base' import { useControlledDialog } from '../../utils/hooks/useControlledDialog' import { RedPacketPluginID } from '../../plugins/RedPacket/constants' import { ITO_PluginID } from '../../plugins/ITO/constants' @@ -141,7 +141,7 @@ export function ApplicationBoard({ secondEntries, secondEntryChainTabs }: MaskAp // #region Encrypted message const openEncryptedMessage = useCallback( (id?: string) => - MaskMessages.events.requestComposition.sendToLocal({ + CrossIsolationMessages.events.requestComposition.sendToLocal({ reason: 'timeline', open: true, options: { diff --git a/packages/mask/src/plugins/Wallet/SNSAdaptor/WalletStatusDialog/index.tsx b/packages/mask/src/plugins/Wallet/SNSAdaptor/WalletStatusDialog/index.tsx index 90227a1f8b07..e228a5248a86 100644 --- a/packages/mask/src/plugins/Wallet/SNSAdaptor/WalletStatusDialog/index.tsx +++ b/packages/mask/src/plugins/Wallet/SNSAdaptor/WalletStatusDialog/index.tsx @@ -2,13 +2,13 @@ import { useCallback } from 'react' import { DialogActions, DialogContent, Typography } from '@mui/material' import ErrorIcon from '@mui/icons-material/Error' import { useRemoteControlledDialog } from '@masknet/shared-base-ui' +import { CrossIsolationMessages } from '@masknet/shared-base' import { useChainIdValid } from '@masknet/web3-shared-evm' import { makeStyles } from '@masknet/theme' import { InjectedDialog } from '../../../../components/shared/InjectedDialog' import { WalletStatusBox } from '../../../../components/shared/WalletStatusBox' import { useI18N } from '../../../../utils' import { WalletMessages } from '../../messages' -import { MaskMessages } from '../../../../utils/messages' import { ApplicationBoard } from '../../../../components/shared/ApplicationBoard' const useStyles = makeStyles()((theme) => ({ @@ -51,7 +51,7 @@ export function WalletStatusDialog(props: WalletStatusDialogProps) { const closeDialog = useCallback(() => { _closeDialog() - MaskMessages.events.requestComposition.sendToLocal({ + CrossIsolationMessages.events.requestComposition.sendToLocal({ reason: 'timeline', open: false, }) diff --git a/packages/mask/src/social-network-adaptor/facebook.com/automation/openComposeBox.ts b/packages/mask/src/social-network-adaptor/facebook.com/automation/openComposeBox.ts index 2bd58acc75d6..1e789aee829b 100644 --- a/packages/mask/src/social-network-adaptor/facebook.com/automation/openComposeBox.ts +++ b/packages/mask/src/social-network-adaptor/facebook.com/automation/openComposeBox.ts @@ -1,5 +1,5 @@ import { LiveSelector } from '@dimensiondev/holoflows-kit' -import { MaskMessages, CompositionRequest } from '../../../utils/messages' +import { CrossIsolationMessages, CompositionRequest } from '@masknet/shared-base' import { i18n } from '../../../../shared-ui/locales_legacy' import { makeTypedMessageText, SerializableTypedMessages } from '@masknet/typed-message' import { delay, waitDocumentReadyState } from '@dimensiondev/kit' @@ -56,7 +56,7 @@ export async function taskOpenComposeBoxFacebook( } await delay(2000) - MaskMessages.events.requestComposition.sendToLocal({ + CrossIsolationMessages.events.requestComposition.sendToLocal({ reason: 'popup', open: true, content: typeof content === 'string' ? makeTypedMessageText(content) : content, diff --git a/packages/mask/src/social-network-adaptor/facebook.com/injection/Composition.tsx b/packages/mask/src/social-network-adaptor/facebook.com/injection/Composition.tsx index 7ebdf51ce00b..1ee7a87a0858 100644 --- a/packages/mask/src/social-network-adaptor/facebook.com/injection/Composition.tsx +++ b/packages/mask/src/social-network-adaptor/facebook.com/injection/Composition.tsx @@ -1,10 +1,10 @@ import { useCallback } from 'react' import { LiveSelector, MutationObserverWatcher } from '@dimensiondev/holoflows-kit' +import { CrossIsolationMessages } from '@masknet/shared-base' import { createReactRootShadowed } from '../../../utils/shadow-root/renderInShadowRoot' import { Composition } from '../../../components/CompositionDialog/Composition' import { isMobileFacebook } from '../utils/isMobile' import { PostDialogHint } from '../../../components/InjectedComponents/PostDialogHint' -import { MaskMessages } from '../../../utils/messages' import { startWatch } from '../../../utils/watcher' import { taskOpenComposeBoxFacebook } from '../automation/openComposeBox' import { makeStyles } from '@masknet/theme' @@ -53,7 +53,7 @@ export function injectCompositionFacebook(signal: AbortSignal) { signal.addEventListener( 'abort', - MaskMessages.events.requestComposition.on((data) => { + CrossIsolationMessages.events.requestComposition.on((data) => { if (data.reason === 'popup') return if (data.open === false) return taskOpenComposeBoxFacebook(data.content || '', data.options) @@ -63,7 +63,7 @@ export function injectCompositionFacebook(signal: AbortSignal) { function UI() { const { classes } = useStyles() const onHintButtonClicked = useCallback( - () => MaskMessages.events.requestComposition.sendToLocal({ reason: 'popup', open: true }), + () => CrossIsolationMessages.events.requestComposition.sendToLocal({ reason: 'popup', open: true }), [], ) return ( diff --git a/packages/mask/src/social-network-adaptor/instagram.com/injection/Entry.tsx b/packages/mask/src/social-network-adaptor/instagram.com/injection/Entry.tsx index eef3f66a41ab..f817252195cc 100644 --- a/packages/mask/src/social-network-adaptor/instagram.com/injection/Entry.tsx +++ b/packages/mask/src/social-network-adaptor/instagram.com/injection/Entry.tsx @@ -1,9 +1,9 @@ import { Fab, styled } from '@mui/material' import { Create } from '@mui/icons-material' +import { CrossIsolationMessages } from '@masknet/shared-base' import { Composition } from '../../../components/CompositionDialog/Composition' import { useState, useEffect } from 'react' import { LiveSelector, MutationObserverWatcher } from '@dimensiondev/holoflows-kit' -import { MaskMessages } from '../../../utils' const Container = styled('div')` position: fixed; @@ -30,7 +30,7 @@ export function Entry() { { - MaskMessages.events.requestComposition.sendToLocal({ open: true, reason: 'timeline' }) + CrossIsolationMessages.events.requestComposition.sendToLocal({ open: true, reason: 'timeline' }) }}> Create with Mask diff --git a/packages/mask/src/social-network-adaptor/minds.com/automation/openComposeBox.ts b/packages/mask/src/social-network-adaptor/minds.com/automation/openComposeBox.ts index 660925f17e3b..8194b804fa08 100644 --- a/packages/mask/src/social-network-adaptor/minds.com/automation/openComposeBox.ts +++ b/packages/mask/src/social-network-adaptor/minds.com/automation/openComposeBox.ts @@ -1,7 +1,7 @@ import { makeTypedMessageText, SerializableTypedMessages } from '@masknet/typed-message' +import { CrossIsolationMessages, CompositionRequest } from '@masknet/shared-base' import { delay, waitDocumentReadyState } from '@dimensiondev/kit' import { i18n } from '../../../../shared-ui/locales_legacy' -import { MaskMessages, CompositionRequest } from '../../../utils/messages' import { composeButtonSelector, composeDialogIndicatorSelector, composeTextareaSelector } from '../utils/selector' export async function openComposeBoxMinds( @@ -26,7 +26,7 @@ export async function openComposeBoxMinds( } await delay(800) - MaskMessages.events.requestComposition.sendToLocal({ + CrossIsolationMessages.events.requestComposition.sendToLocal({ reason: 'popup', open: true, content: typeof content === 'string' ? makeTypedMessageText(content) : content, diff --git a/packages/mask/src/social-network-adaptor/minds.com/injection/PostDialogHint.tsx b/packages/mask/src/social-network-adaptor/minds.com/injection/PostDialogHint.tsx index 78bc4a0e4338..88c409cabefd 100644 --- a/packages/mask/src/social-network-adaptor/minds.com/injection/PostDialogHint.tsx +++ b/packages/mask/src/social-network-adaptor/minds.com/injection/PostDialogHint.tsx @@ -1,8 +1,8 @@ import { LiveSelector, MutationObserverWatcher } from '@dimensiondev/holoflows-kit' import { makeStyles } from '@masknet/theme' +import { CrossIsolationMessages } from '@masknet/shared-base' import { useCallback } from 'react' import { PostDialogHint } from '../../../components/InjectedComponents/PostDialogHint' -import { MaskMessages } from '../../../utils/messages' import { createReactRootShadowed } from '../../../utils/shadow-root/renderInShadowRoot' import { startWatch } from '../../../utils/watcher' import { postEditorInPopupSelector, postEditorInTimelineSelector } from '../utils/selector' @@ -45,7 +45,7 @@ function PostDialogHintAtMinds({ reason }: { reason: 'timeline' | 'popup' }) { const { classes } = useStyles({ reason }) const onHintButtonClicked = useCallback( - () => MaskMessages.events.requestComposition.sendToLocal({ reason, open: true }), + () => CrossIsolationMessages.events.requestComposition.sendToLocal({ reason, open: true }), [reason], ) return ( diff --git a/packages/mask/src/social-network-adaptor/twitter.com/automation/openComposeBox.ts b/packages/mask/src/social-network-adaptor/twitter.com/automation/openComposeBox.ts index a40eda021270..8312260fc5d5 100644 --- a/packages/mask/src/social-network-adaptor/twitter.com/automation/openComposeBox.ts +++ b/packages/mask/src/social-network-adaptor/twitter.com/automation/openComposeBox.ts @@ -1,11 +1,11 @@ -import { MaskMessages, CompositionRequest } from '../../../utils/messages' +import { CrossIsolationMessages, CompositionRequest } from '@masknet/shared-base' import { makeTypedMessageText, SerializableTypedMessages } from '@masknet/typed-message' export function openComposeBoxTwitter( content: string | SerializableTypedMessages, options?: CompositionRequest['options'], ) { - MaskMessages.events.requestComposition.sendToLocal({ + CrossIsolationMessages.events.requestComposition.sendToLocal({ reason: 'timeline', open: true, content: typeof content === 'string' ? makeTypedMessageText(content) : content, diff --git a/packages/mask/src/social-network-adaptor/twitter.com/injection/PostDialogHint.tsx b/packages/mask/src/social-network-adaptor/twitter.com/injection/PostDialogHint.tsx index 2eb6d896327d..5fc8d4baed8d 100644 --- a/packages/mask/src/social-network-adaptor/twitter.com/injection/PostDialogHint.tsx +++ b/packages/mask/src/social-network-adaptor/twitter.com/injection/PostDialogHint.tsx @@ -1,9 +1,9 @@ import { useCallback, useEffect, useState } from 'react' import { MutationObserverWatcher, LiveSelector } from '@dimensiondev/holoflows-kit' +import { CrossIsolationMessages } from '@masknet/shared-base' import { isReplyPageSelector, postEditorInPopupSelector, searchReplyToolbarSelector } from '../utils/selector' import { createReactRootShadowed } from '../../../utils/shadow-root/renderInShadowRoot' import { PostDialogHint } from '../../../components/InjectedComponents/PostDialogHint' -import { MaskMessages } from '../../../utils/messages' import { startWatch } from '../../../utils/watcher' import { makeStyles, MaskColorVar } from '@masknet/theme' import { alpha } from '@mui/material' @@ -61,7 +61,7 @@ function PostDialogHintAtTwitter({ reason }: { reason: 'timeline' | 'popup' }) { t('setup_guide_say_hello_follow', { account: '@realMaskNetwork' }), ) - MaskMessages.events.requestComposition.sendToLocal({ + CrossIsolationMessages.events.requestComposition.sendToLocal({ reason: isReplyPageSelector() ? 'reply' : reason, open: true, content, diff --git a/packages/shared-base/src/Messages/Shared.ts b/packages/shared-base/src/Messages/Shared.ts index 1bc24f53efe0..3ad844c53345 100644 --- a/packages/shared-base/src/Messages/Shared.ts +++ b/packages/shared-base/src/Messages/Shared.ts @@ -1,4 +1,5 @@ import { WebExtensionMessage } from '@dimensiondev/holoflows-kit' +import type { CompositionRequest } from './Mask' /** * @deprecated @@ -14,4 +15,6 @@ import { WebExtensionMessage } from '@dimensiondev/holoflows-kit' // TODO: find a way to use a good API for cross isolation communication. export const CrossIsolationMessages = new WebExtensionMessage({ domain: '_' }) -export interface CrossIsolationEvents {} +export interface CrossIsolationEvents { + requestComposition: CompositionRequest +} From 4abe6d24a31d74e45e322992140c04aa23293aad Mon Sep 17 00:00:00 2001 From: septs Date: Mon, 28 Mar 2022 18:10:23 +0800 Subject: [PATCH 11/42] refactor: open window (#5972) * refactor: open window * fix: typo * revert: pnpm-lock * fix: typo * fix: typo --- .../PageFrame/FeaturePromotions/index.tsx | 4 +- .../components/Welcome/index.tsx | 5 +-- packages/dashboard/src/pages/Labs/index.tsx | 7 +--- .../components/PostHistory/Placeholder.tsx | 3 +- .../dashboard/src/pages/Welcome/index.tsx | 5 +-- .../components/shared/ApplicationBoard.tsx | 8 ++-- .../popups/pages/Wallet/TokenDetail/index.tsx | 34 +++++++--------- .../plugins/Avatar/SNSAdaptor/NFTBadge.tsx | 3 +- .../UI/components/ProviderIconClickBait.tsx | 4 +- .../plugins/ITO/SNSAdaptor/ClaimAllDialog.tsx | 4 +- .../src/plugins/ITO/SNSAdaptor/SwapDialog.tsx | 4 +- .../NextID/components/Tip/TipDialog.tsx | 3 +- .../RedPacket/SNSAdaptor/RedPacketNft.tsx | 7 +--- .../Trader/SNSAdaptor/trending/PriceChart.tsx | 5 +-- .../facebook.com/shared.ts | 14 ++++--- .../minds.com/shared.ts | 10 +++-- .../injection/NFT/NFTAvatarInTwitter.tsx | 3 +- .../twitter.com/shared.ts | 20 ++++++++-- .../mask/src/social-network-adaptor/utils.ts | 15 ------- packages/shared-base-ui/src/bom/index.ts | 1 + .../shared-base-ui/src/bom/open-window.ts | 40 +++++++++++++++++++ packages/shared-base-ui/src/index.ts | 1 + 22 files changed, 118 insertions(+), 82 deletions(-) create mode 100644 packages/shared-base-ui/src/bom/index.ts create mode 100644 packages/shared-base-ui/src/bom/open-window.ts diff --git a/packages/dashboard/src/components/PageFrame/FeaturePromotions/index.tsx b/packages/dashboard/src/components/PageFrame/FeaturePromotions/index.tsx index a8b8a77321f6..1dd049428263 100644 --- a/packages/dashboard/src/components/PageFrame/FeaturePromotions/index.tsx +++ b/packages/dashboard/src/components/PageFrame/FeaturePromotions/index.tsx @@ -1,7 +1,7 @@ import { memo, useCallback, useMemo } from 'react' import { useNavigate } from 'react-router-dom' import { makeStyles } from '@masknet/theme' -import { useRemoteControlledDialog } from '@masknet/shared-base-ui' +import { openWindow, useRemoteControlledDialog } from '@masknet/shared-base-ui' import { useAccount } from '@masknet/web3-shared-evm' import { PluginMessages, Services } from '../../../API' import { PersonaContext } from '../../../pages/Personas/hooks/usePersonaContext' @@ -64,7 +64,7 @@ export const FeaturePromotions = memo(() => { connectPersona(currentPersona.identifier, EnhanceableSite.Twitter) } - const openMaskNetwork = () => window.open('https://twitter.com/realMaskNetwork') + const openMaskNetwork = () => openWindow('https://twitter.com/realMaskNetwork') return (
diff --git a/packages/dashboard/src/pages/CreateMaskWallet/components/Welcome/index.tsx b/packages/dashboard/src/pages/CreateMaskWallet/components/Welcome/index.tsx index f5616814e83b..bb1065d382b4 100644 --- a/packages/dashboard/src/pages/CreateMaskWallet/components/Welcome/index.tsx +++ b/packages/dashboard/src/pages/CreateMaskWallet/components/Welcome/index.tsx @@ -6,6 +6,7 @@ import { useDashboardI18N } from '../../../../locales' import { Button } from '@mui/material' import { MaskNotSquareIcon } from '@masknet/icons' import urlcat from 'urlcat' +import { openWindow } from '@masknet/shared-base-ui' const Content = styled('div')` width: 100%; @@ -98,9 +99,7 @@ const Welcome = memo(() => { link?.addEventListener('click', handleLinkClick) } - const handleLinkClick = () => { - window.open(MASK_PRIVACY_POLICY) - } + const handleLinkClick = () => openWindow(MASK_PRIVACY_POLICY) useEffect( () => () => { diff --git a/packages/dashboard/src/pages/Labs/index.tsx b/packages/dashboard/src/pages/Labs/index.tsx index 082e0ce68b52..4375ecc1cd72 100644 --- a/packages/dashboard/src/pages/Labs/index.tsx +++ b/packages/dashboard/src/pages/Labs/index.tsx @@ -23,7 +23,7 @@ import { useDashboardI18N } from '../../locales' import MarketTrendSettingDialog from './components/MarketTrendSettingDialog' import { useAccount } from '@masknet/web3-shared-evm' import { Messages, Services, PluginMessages } from '../../API' -import { useRemoteControlledDialog } from '@masknet/shared-base-ui' +import { openWindow, useRemoteControlledDialog } from '@masknet/shared-base-ui' import { TUTORIAL_URLS_EN } from './constants' import { ContentContainer } from '../../components/ContentContainer' import { WalletStateBar } from '../Wallets/components/WalletStateBar' @@ -230,10 +230,7 @@ export default function Plugins() { } function onTutorial(id: string) { - const url = TUTORIAL_URLS_EN[id] - if (url) { - window.open(url, '_blank', 'noopener noreferrer') - } + openWindow(TUTORIAL_URLS_EN[id]) } function onTutorialDialogClose(checked: boolean) { diff --git a/packages/dashboard/src/pages/Personas/components/PostHistory/Placeholder.tsx b/packages/dashboard/src/pages/Personas/components/PostHistory/Placeholder.tsx index 7b8cb9115e1c..c532fe947d6d 100644 --- a/packages/dashboard/src/pages/Personas/components/PostHistory/Placeholder.tsx +++ b/packages/dashboard/src/pages/Personas/components/PostHistory/Placeholder.tsx @@ -4,6 +4,7 @@ import { EmptyIcon } from '@masknet/icons' import { useDashboardI18N } from '../../../../locales' import urlcat from 'urlcat' import { MaskColorVar } from '@masknet/theme' +import { openWindow } from '@masknet/shared-base-ui' interface PlaceholderProps { network: string @@ -13,7 +14,7 @@ export const Placeholder = memo(({ network }) => { const t = useDashboardI18N() const url = urlcat('https://www.:network', { network: network }) - const handleClick = () => window.open(url) + const handleClick = () => openWindow(url) return ( diff --git a/packages/dashboard/src/pages/Welcome/index.tsx b/packages/dashboard/src/pages/Welcome/index.tsx index bd4987db60bc..9e4893222ee7 100644 --- a/packages/dashboard/src/pages/Welcome/index.tsx +++ b/packages/dashboard/src/pages/Welcome/index.tsx @@ -6,6 +6,7 @@ import { styled } from '@mui/material/styles' import { memo, MutableRefObject, useEffect, useMemo, useRef } from 'react' import { useDashboardI18N } from '../../locales' import links from '../../components/FooterLine/links.json' +import { openWindow } from '@masknet/shared-base-ui' const Content = styled('div')(({ theme }) => ({ padding: `${theme.spacing(1)} ${theme.spacing(4)}`, @@ -71,9 +72,7 @@ export default function Welcome() { link?.addEventListener('click', handleLinkClick) } - const handleLinkClick = () => { - window.open(links.MASK_PRIVACY_POLICY) - } + const handleLinkClick = () => openWindow(links.MASK_PRIVACY_POLICY) return ( window.open('https://bridge.mask.io/#/', '_blank', 'noopener noreferrer'), + () => openWindow('https://bridge.mask.io'), undefined, isNotEvm, false, @@ -277,7 +277,7 @@ export function ApplicationBoard({ secondEntries, secondEntryChainTabs }: MaskAp createEntry( 'MaskBox', new URL('./assets/mask_box.png', import.meta.url).toString(), - () => window.open('https://box.mask.io/#/', '_blank', 'noopener noreferrer'), + () => openWindow('https://box.mask.io'), undefined, isNotEvm, false, @@ -314,7 +314,7 @@ export function ApplicationBoard({ secondEntries, secondEntryChainTabs }: MaskAp createEntry( 'MaskBox', new URL('./assets/mask_box.png', import.meta.url).toString(), - () => window.open('https://box.mask.io/#/', '_blank', 'noopener noreferrer'), + () => openWindow('https://box.mask.io'), undefined, false, false, diff --git a/packages/mask/src/extension/popups/pages/Wallet/TokenDetail/index.tsx b/packages/mask/src/extension/popups/pages/Wallet/TokenDetail/index.tsx index 42840cfa30f6..ef3bd91b5fa8 100644 --- a/packages/mask/src/extension/popups/pages/Wallet/TokenDetail/index.tsx +++ b/packages/mask/src/extension/popups/pages/Wallet/TokenDetail/index.tsx @@ -23,6 +23,7 @@ import Services from '../../../../service' import { compact, intersectionWith } from 'lodash-unified' import urlcat from 'urlcat' import { ActivityList } from '../components/ActivityList' +import { openWindow } from '@masknet/shared-base-ui' const useStyles = makeStyles()({ content: { @@ -93,30 +94,25 @@ const TokenDetail = memo(() => { open: 'Transak', code: currentToken?.token.symbol ?? currentToken?.token.name, }) - window.open(browser.runtime.getURL(url), 'BUY_DIALOG', 'noopener noreferrer') + openWindow(browser.runtime.getURL(url), 'BUY_DIALOG') } }, [wallet?.address, isActiveSocialNetwork, currentToken]) const openSwapDialog = useCallback(async () => { - window.open( - browser.runtime.getURL( - urlcat( - 'popups.html#/', - PopupRoutes.Swap, - !isSameAddress(nativeToken?.address, currentToken?.token.address) - ? { - id: currentToken?.token.address, - name: currentToken?.token.name, - symbol: currentToken?.token.symbol, - contract_address: currentToken?.token.address, - decimals: currentToken?.token.decimals, - } - : {}, - ), - ), - 'SWAP_DIALOG', - 'noopener noreferrer', + const url = urlcat( + 'popups.html#/', + PopupRoutes.Swap, + !isSameAddress(nativeToken?.address, currentToken?.token.address) + ? { + id: currentToken?.token.address, + name: currentToken?.token.name, + symbol: currentToken?.token.symbol, + contract_address: currentToken?.token.address, + decimals: currentToken?.token.decimals, + } + : {}, ) + openWindow(browser.runtime.getURL(url), 'SWAP_DIALOG') }, [currentToken, nativeToken]) if (!currentToken) return null diff --git a/packages/mask/src/plugins/Avatar/SNSAdaptor/NFTBadge.tsx b/packages/mask/src/plugins/Avatar/SNSAdaptor/NFTBadge.tsx index be85dd024b92..42a0d94f1b07 100644 --- a/packages/mask/src/plugins/Avatar/SNSAdaptor/NFTBadge.tsx +++ b/packages/mask/src/plugins/Avatar/SNSAdaptor/NFTBadge.tsx @@ -1,3 +1,4 @@ +import { openWindow } from '@masknet/shared-base-ui' import { makeStyles, useStylesExtends } from '@masknet/theme' import { resolveOpenSeaLink } from '@masknet/web3-shared-evm' import Link from '@mui/material/Link' @@ -42,7 +43,7 @@ export function NFTBadge(props: NFTBadgeProps) { className={classes.root} onClick={(e) => { e.preventDefault() - window.open(resolveOpenSeaLink(avatar.address, avatar.tokenId), '_blank') + openWindow(resolveOpenSeaLink(avatar.address, avatar.tokenId)) }}> { - window.open(resolveTransactionLinkOnExplorer(chainId, hash), '_blank', 'noopener noreferrer') + openWindow(resolveTransactionLinkOnExplorer(chainId, hash)) }, 2000) return } diff --git a/packages/mask/src/plugins/ITO/SNSAdaptor/SwapDialog.tsx b/packages/mask/src/plugins/ITO/SNSAdaptor/SwapDialog.tsx index 0863d75fc0b1..c8eb83b16790 100644 --- a/packages/mask/src/plugins/ITO/SNSAdaptor/SwapDialog.tsx +++ b/packages/mask/src/plugins/ITO/SNSAdaptor/SwapDialog.tsx @@ -4,7 +4,7 @@ import { v4 as uuid } from 'uuid' import { CircularProgress, Slider, Typography } from '@mui/material' import { makeStyles, useStylesExtends } from '@masknet/theme' import { useI18N } from '../../../utils' -import { useRemoteControlledDialog } from '@masknet/shared-base-ui' +import { openWindow, useRemoteControlledDialog } from '@masknet/shared-base-ui' import ActionButton from '../../../extension/options-page/DashboardComponents/ActionButton' import { ChainId, @@ -239,7 +239,7 @@ export function SwapDialog(props: SwapDialogProps) { if (swapState.type === TransactionStateType.HASH) { const { hash } = swapState setTimeout(() => { - window.open(resolveTransactionLinkOnExplorer(chainId, hash), '_blank', 'noopener noreferrer') + openWindow(resolveTransactionLinkOnExplorer(chainId, hash)) }, 2000) return } diff --git a/packages/mask/src/plugins/NextID/components/Tip/TipDialog.tsx b/packages/mask/src/plugins/NextID/components/Tip/TipDialog.tsx index a444087be0fc..b48584490c84 100644 --- a/packages/mask/src/plugins/NextID/components/Tip/TipDialog.tsx +++ b/packages/mask/src/plugins/NextID/components/Tip/TipDialog.tsx @@ -1,6 +1,7 @@ import { SuccessIcon } from '@masknet/icons' import { PluginId, useActivatedPlugin, usePluginIDContext } from '@masknet/plugin-infra' import { NFTCardStyledAssetPlayer } from '@masknet/shared' +import { openWindow } from '@masknet/shared-base-ui' import { makeStyles } from '@masknet/theme' import { EMPTY_LIST, TransactionStateType, useChainId, useERC721TokenDetailed } from '@masknet/web3-shared-evm' import { DialogContent, Typography } from '@mui/material' @@ -142,7 +143,7 @@ export function TipDialog({ open = false, onClose }: TipDialogProps) { }, [sendState.type]) const handleConfirm = useCallback(() => { - window.open(shareLink) + openWindow(shareLink) openConfirmModal(false) onClose?.() }, [shareLink, onClose]) diff --git a/packages/mask/src/plugins/RedPacket/SNSAdaptor/RedPacketNft.tsx b/packages/mask/src/plugins/RedPacket/SNSAdaptor/RedPacketNft.tsx index 81fbde4d68bc..996f2814db13 100644 --- a/packages/mask/src/plugins/RedPacket/SNSAdaptor/RedPacketNft.tsx +++ b/packages/mask/src/plugins/RedPacket/SNSAdaptor/RedPacketNft.tsx @@ -22,6 +22,7 @@ import { activatedSocialNetworkUI } from '../../../social-network' import { isTwitter } from '../../../social-network-adaptor/twitter.com/base' import { isFacebook } from '../../../social-network-adaptor/facebook.com/base' import { NFTCardStyledAssetPlayer } from '@masknet/shared' +import { openWindow } from '@masknet/shared-base-ui' const useStyles = makeStyles()((theme) => ({ root: { @@ -261,11 +262,7 @@ export function RedPacketNft({ payload }: RedPacketNftProps) { const isClaiming = claimState.type === TransactionStateType.WAIT_FOR_CONFIRMING const openAddressLinkOnExplorer = useCallback(() => { - window.open( - resolveAddressLinkOnExplorer(payload.chainId, payload.contractAddress), - '_blank', - 'noopener noreferrer', - ) + openWindow(resolveAddressLinkOnExplorer(payload.chainId, payload.contractAddress)) }, [payload]) const [sourceType, setSourceType] = useState('') diff --git a/packages/mask/src/plugins/Trader/SNSAdaptor/trending/PriceChart.tsx b/packages/mask/src/plugins/Trader/SNSAdaptor/trending/PriceChart.tsx index 3c15c3c6464b..bd58072d5ddc 100644 --- a/packages/mask/src/plugins/Trader/SNSAdaptor/trending/PriceChart.tsx +++ b/packages/mask/src/plugins/Trader/SNSAdaptor/trending/PriceChart.tsx @@ -7,6 +7,7 @@ import { useI18N } from '../../../../utils' import type { Coin, Currency, Stat } from '../../types' import { useDimension, Dimension } from '../../../hooks/useDimension' import { usePriceLineChart } from '../../../hooks/usePriceLineChart' +import { openWindow } from '@masknet/shared-base-ui' const DEFAULT_DIMENSION: Dimension = { top: 32, @@ -110,9 +111,7 @@ export function PriceChart(props: PriceChartProps) { viewBox={`0 0 ${dimension.width} ${dimension.height}`} preserveAspectRatio="xMidYMid meet" onClick={() => { - props.stats.length && - props.coin?.platform_url && - window.open(props.coin.platform_url, '_blank', 'noopener noreferrer') + props.stats.length && openWindow(props.coin?.platform_url) }} /> diff --git a/packages/mask/src/social-network-adaptor/facebook.com/shared.ts b/packages/mask/src/social-network-adaptor/facebook.com/shared.ts index 18a3e5fa00c0..305dcbc30890 100644 --- a/packages/mask/src/social-network-adaptor/facebook.com/shared.ts +++ b/packages/mask/src/social-network-adaptor/facebook.com/shared.ts @@ -4,6 +4,8 @@ import { getPostUrlAtFacebook, isValidFacebookUsername } from './utils/parse-use import { PostIdentifier, ProfileIdentifier } from '@masknet/shared-base' import { deconstructPayload } from '../../utils' import { createSNSAdaptorSpecializedPostContext } from '../../social-network/utils/create-post-context' +import { openWindow } from '@masknet/shared-base-ui' +import urlcat from 'urlcat' const getPostURL = (post: PostIdentifier): URL | null => { if (post.identifier instanceof ProfileIdentifier) @@ -19,14 +21,14 @@ export const facebookShared: SocialNetwork.Shared & SocialNetwork.Base = { textPayloadPostProcessor: undefined, getPostURL, share(message) { - const url = this.getShareLinkURL!(message) - window.open(url, '_blank', 'noopener noreferrer') + openWindow(this.getShareLinkURL?.(message)) }, getShareLinkURL(message) { - const url = new URL('https://www.facebook.com/sharer/sharer.php') - url.searchParams.set('quote', message) - url.searchParams.set('u', 'mask.io') - return url + const url = urlcat('https://www.facebook.com/sharer/sharer.php', { + quote: message, + u: 'mask.io', + }) + return new URL(url) }, createPostContext: createSNSAdaptorSpecializedPostContext({ payloadParser: deconstructPayload, diff --git a/packages/mask/src/social-network-adaptor/minds.com/shared.ts b/packages/mask/src/social-network-adaptor/minds.com/shared.ts index bbc72b7a3382..ab4e841712e5 100644 --- a/packages/mask/src/social-network-adaptor/minds.com/shared.ts +++ b/packages/mask/src/social-network-adaptor/minds.com/shared.ts @@ -1,4 +1,6 @@ import type { PostIdentifier } from '@masknet/shared-base' +import { openWindow } from '@masknet/shared-base-ui' +import urlcat from 'urlcat' import type { SocialNetwork } from '../../social-network/types' import { createSNSAdaptorSpecializedPostContext } from '../../social-network/utils/create-post-context' import { deconstructPayload } from '../../utils' @@ -17,11 +19,13 @@ export const mindsShared: SocialNetwork.Shared & SocialNetwork.Base = { textPayloadPostProcessor: undefined, getPostURL, share(message) { - const url = this.getShareLinkURL!(message) - window.open(url, '_blank', 'noopener noreferrer') + openWindow(this.getShareLinkURL?.(message)) }, getShareLinkURL(message) { - return new URL(`https://www.minds.com/newsfeed/subscriptions?intentUrl=${encodeURIComponent(message)}`) + const url = urlcat('https://www.minds.com/newsfeed/subscriptions', { + intentUrl: message, + }) + return new URL(url) }, createPostContext: createSNSAdaptorSpecializedPostContext({ payloadParser: deconstructPayload, diff --git a/packages/mask/src/social-network-adaptor/twitter.com/injection/NFT/NFTAvatarInTwitter.tsx b/packages/mask/src/social-network-adaptor/twitter.com/injection/NFT/NFTAvatarInTwitter.tsx index debe79e92c43..530a742310ca 100644 --- a/packages/mask/src/social-network-adaptor/twitter.com/injection/NFT/NFTAvatarInTwitter.tsx +++ b/packages/mask/src/social-network-adaptor/twitter.com/injection/NFT/NFTAvatarInTwitter.tsx @@ -15,6 +15,7 @@ import { useAsync, useLocation, useUpdateEffect, useWindowSize } from 'react-use import { rainbowBorderKeyFrames } from '../../../../plugins/Avatar/SNSAdaptor/RainbowBox' import { trim } from 'lodash-unified' import { RSS3_KEY_SNS } from '../../../../plugins/Avatar/constants' +import { openWindow } from '@masknet/shared-base-ui' export function injectNFTAvatarInTwitter(signal: AbortSignal) { const watcher = new MutationObserverWatcher(searchTwitterAvatarSelector()) @@ -194,7 +195,7 @@ function NFTAvatarInTwitter() { if (!avatar || !linkParentDom || !showAvatar) return const handler = () => { - window.open(resolveOpenSeaLink(avatar.address, avatar.tokenId), '_blank') + openWindow(resolveOpenSeaLink(avatar.address, avatar.tokenId)) } linkParentDom.addEventListener('click', handler) diff --git a/packages/mask/src/social-network-adaptor/twitter.com/shared.ts b/packages/mask/src/social-network-adaptor/twitter.com/shared.ts index de652947450b..1b1ce5795335 100644 --- a/packages/mask/src/social-network-adaptor/twitter.com/shared.ts +++ b/packages/mask/src/social-network-adaptor/twitter.com/shared.ts @@ -1,8 +1,9 @@ import { PostIdentifier, ProfileIdentifier } from '@masknet/shared-base' +import { openWindow } from '@masknet/shared-base-ui' +import urlcat from 'urlcat' import type { SocialNetwork } from '../../social-network/types' import { createSNSAdaptorSpecializedPostContext } from '../../social-network/utils/create-post-context' import { deconstructPayload } from '../../utils' -import { createCenterWindowConfig } from '../utils' import { twitterBase } from './base' import { twitterEncoding } from './encoding' import { usernameValidator } from './utils/user' @@ -27,12 +28,23 @@ export const twitterShared: SocialNetwork.Shared & SocialNetwork.Base = { }, getPostURL, share(text) { - const config = createCenterWindowConfig(700, 520) const url = this.getShareLinkURL!(text) - window.open(url, 'share', config) || window.location.assign(url) + const width = 700 + const height = 520 + const openedWindow = openWindow(url, 'share', { + width, + height, + screenX: window.screenX + (window.innerWidth - width) / 2, + screenY: window.screenY + (window.innerHeight - height) / 2, + behaviors: { toolbar: true, status: true, resizable: true, scrollbars: true }, + }) + if (openedWindow === null) { + location.assign(url) + } }, getShareLinkURL(message) { - return new URL(`https://twitter.com/intent/tweet?text=${encodeURIComponent(message)}`) + const url = urlcat('https://twitter.com/intent/tweet', { text: message }) + return new URL(url) }, createPostContext: createSNSAdaptorSpecializedPostContext({ payloadParser: deconstructPayload, diff --git a/packages/mask/src/social-network-adaptor/utils.ts b/packages/mask/src/social-network-adaptor/utils.ts index a0e6273f3514..1349c4980437 100644 --- a/packages/mask/src/social-network-adaptor/utils.ts +++ b/packages/mask/src/social-network-adaptor/utils.ts @@ -23,18 +23,3 @@ export const getCurrentIdentifier = () => { globalUIState.profiles.value[0] ) } - -export const createCenterWindowConfig = (width: number, height: number) => { - const x = window.screenX + (window.innerWidth - width) / 2 - const y = window.screenY + (window.innerHeight - height) / 2 - return [ - `screenX=${x}`, - `screenY=${y}`, - 'toolbar=1', - 'status=1', - 'resizable=1', - 'scrollbars=1', - `height=${height}`, - `width=${width}`, - ].join(',') -} diff --git a/packages/shared-base-ui/src/bom/index.ts b/packages/shared-base-ui/src/bom/index.ts new file mode 100644 index 000000000000..d2a7cce6f930 --- /dev/null +++ b/packages/shared-base-ui/src/bom/index.ts @@ -0,0 +1 @@ +export { openWindow } from './open-window' diff --git a/packages/shared-base-ui/src/bom/open-window.ts b/packages/shared-base-ui/src/bom/open-window.ts new file mode 100644 index 000000000000..cf573c57b1b6 --- /dev/null +++ b/packages/shared-base-ui/src/bom/open-window.ts @@ -0,0 +1,40 @@ +type WindowTarget = '_top' | '_self' | '_parent' | '_blank' | string + +interface BehaviorFlags { + popup?: boolean + toolbar?: boolean + status?: boolean + resizable?: boolean + scrollbars?: boolean +} + +interface WindowFeatureFlags { + // Behavior + opener?: boolean + referrer?: boolean + behaviors?: BehaviorFlags + // Dimension + width?: number + height?: number + screenX?: number + screenY?: number +} + +export function openWindow( + url: string | URL | undefined | null, + target: WindowTarget = '_blank', + features: WindowFeatureFlags = {}, +): Window | null { + if (!url) return null + const flags = [] + for (const [name, value] of Object.entries(features.behaviors ?? {})) { + if (value) flags.push(`${name}=1`) + } + if (!features.opener) flags.push('noopener') + if (!features.referrer) flags.push('noreferrer') + if (Number.isFinite(features.width)) flags.push(`width=${features.width}`) + if (Number.isFinite(features.height)) flags.push(`height=${features.height}`) + if (Number.isFinite(features.screenX)) flags.push(`screenX=${features.screenX}`) + if (Number.isFinite(features.screenY)) flags.push(`screenY=${features.screenY}`) + return window.open(url, target, flags.join(' ')) +} diff --git a/packages/shared-base-ui/src/index.ts b/packages/shared-base-ui/src/index.ts index 7aea380be8cc..a28a3c5e7b2d 100644 --- a/packages/shared-base-ui/src/index.ts +++ b/packages/shared-base-ui/src/index.ts @@ -1,2 +1,3 @@ +export * from './bom' export * from './components' export * from './hooks' From 20ee2efe20845d6c2537ede4f340964804f5078e Mon Sep 17 00:00:00 2001 From: septs Date: Mon, 28 Mar 2022 20:00:27 +0800 Subject: [PATCH 12/42] refactor: open window (#5974) * refactor: open window * fix: typo --- packages/dashboard/src/components/FooterLine/index.tsx | 5 +++-- packages/mask/src/extension/debug-page/DebugInfo.tsx | 5 ++--- .../WalletConnectQRCodeDialog/SafariPlatform.tsx | 8 +++----- packages/plugins/FileService/src/SNSAdaptor/Preview.tsx | 3 ++- .../FileService/src/SNSAdaptor/components/Uploaded.tsx | 3 ++- packages/theme/src/Components/Dialogs/Dialog.tsx | 4 ++-- 6 files changed, 14 insertions(+), 14 deletions(-) diff --git a/packages/dashboard/src/components/FooterLine/index.tsx b/packages/dashboard/src/components/FooterLine/index.tsx index b893f706881d..2dcf9bde0f83 100644 --- a/packages/dashboard/src/components/FooterLine/index.tsx +++ b/packages/dashboard/src/components/FooterLine/index.tsx @@ -7,6 +7,7 @@ import { About } from './About' import { Close } from '@mui/icons-material' import { Version } from './Version' import links from './links.json' +import { openWindow } from '@masknet/shared-base-ui' const useStyles = makeStyles()((theme) => ({ navRoot: { @@ -105,9 +106,9 @@ export const FooterLine = memo(() => { const openVersionLink = (event: React.MouseEvent) => { // `MouseEvent.prototype.metaKey` on macOS (`Command` key), Windows (`Windows` key), Linux (`Super` key) if (process.env.channel === 'stable' && !event.metaKey) { - open(`${links.DOWNLOAD_LINK_STABLE_PREFIX}/v${version}`) + openWindow(`${links.DOWNLOAD_LINK_STABLE_PREFIX}/v${version}`) } else { - open(`${links.DOWNLOAD_LINK_UNSTABLE_PREFIX}/${process.env.COMMIT_HASH}`) + openWindow(`${links.DOWNLOAD_LINK_UNSTABLE_PREFIX}/${process.env.COMMIT_HASH}`) } } return ( diff --git a/packages/mask/src/extension/debug-page/DebugInfo.tsx b/packages/mask/src/extension/debug-page/DebugInfo.tsx index abdc3a92b1e6..181889ba9ee1 100644 --- a/packages/mask/src/extension/debug-page/DebugInfo.tsx +++ b/packages/mask/src/extension/debug-page/DebugInfo.tsx @@ -1,6 +1,7 @@ import { map } from 'lodash-unified' import { makeNewBugIssueURL } from './issue' import { useI18N } from '../../utils' +import { openWindow } from '@masknet/shared-base-ui' export const DEBUG_INFO = { 'User Agent': navigator.userAgent, 'Mask Version': process.env.VERSION, @@ -16,9 +17,7 @@ export const DEBUG_INFO = { export const DebugInfo = () => { const { t } = useI18N() - const onNewBugIssue = () => { - open(makeNewBugIssueURL()) - } + const onNewBugIssue = () => openWindow(makeNewBugIssueURL()) return ( <> diff --git a/packages/mask/src/plugins/Wallet/SNSAdaptor/WalletConnectQRCodeDialog/SafariPlatform.tsx b/packages/mask/src/plugins/Wallet/SNSAdaptor/WalletConnectQRCodeDialog/SafariPlatform.tsx index f560d8a699b3..7076453818c2 100644 --- a/packages/mask/src/plugins/Wallet/SNSAdaptor/WalletConnectQRCodeDialog/SafariPlatform.tsx +++ b/packages/mask/src/plugins/Wallet/SNSAdaptor/WalletConnectQRCodeDialog/SafariPlatform.tsx @@ -5,6 +5,8 @@ import { createElement } from 'react' import { useI18N } from '../../../../utils' import { Provider } from '../Provider' import { IMTokenIcon, MetaMaskIcon, RainbowIcon, TrustIcon } from './Icons' +import urlcat from 'urlcat' +import { openWindow } from '@masknet/shared-base-ui' const useStyles = makeStyles()({ container: { display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center' }, @@ -27,11 +29,7 @@ const providers: WalletProvider[] = [ export const SafariPlatform: React.FC<{ uri: string }> = ({ uri }) => { const { t } = useI18N() const { classes } = useStyles() - const makeConnect = (link: string) => () => { - const url = new URL(link) - url.searchParams.set('uri', uri) - open(url.toString()) - } + const makeConnect = (link: string) => () => openWindow(urlcat(link, { uri })) const descriptionMapping: Record = { MetaMask: t('plugin_wallet_connect_safari_metamask'), Rainbow: t('plugin_wallet_connect_safari_rainbow'), diff --git a/packages/plugins/FileService/src/SNSAdaptor/Preview.tsx b/packages/plugins/FileService/src/SNSAdaptor/Preview.tsx index 808bb952cbb7..f10a66f1ed4a 100644 --- a/packages/plugins/FileService/src/SNSAdaptor/Preview.tsx +++ b/packages/plugins/FileService/src/SNSAdaptor/Preview.tsx @@ -7,6 +7,7 @@ import { CopyableCode } from './components/Copyable' import type { FileInfo } from '../types' import { resolveGatewayAPI } from '../helpers' import urlcat from 'urlcat' +import { openWindow } from '@masknet/shared-base-ui' const useStyles = makeStyles()((theme) => ({ root: { @@ -64,7 +65,7 @@ export function Preview({ info }: { info: FileInfo }) { const onClick = (event: React.MouseEvent) => { event.preventDefault() event.stopPropagation() - open(info.key ? `${link}#${info.key}` : link) + openWindow(info.key ? `${link}#${info.key}` : link) } return ( { const linkPrefix = resolveGatewayAPI(state.provider) const link = urlcat(linkPrefix, '/:txId', { txId: state.landingTxID }) - open(state.key ? `${link}#${state.key}` : link) + openWindow(state.key ? `${link}#${state.key}` : link) } return ( diff --git a/packages/theme/src/Components/Dialogs/Dialog.tsx b/packages/theme/src/Components/Dialogs/Dialog.tsx index b709269a18e4..2821bf95166c 100644 --- a/packages/theme/src/Components/Dialogs/Dialog.tsx +++ b/packages/theme/src/Components/Dialogs/Dialog.tsx @@ -41,8 +41,8 @@ export const MaskDialog = memo((props: MaskDialogProps) => { }) export function useMaskDialog(title: string, content: ReactNode, actions: ReactNode) { - const [isOpen, open] = useState(false) - const onClose = useCallback(() => open(false), []) + const [isOpen, setOpen] = useState(false) + const onClose = useCallback(() => setOpen(false), []) return ( {content} From e6f14a2bc3a24f4d8c88ad5e307d7d729a99610f Mon Sep 17 00:00:00 2001 From: zhouhanseng Date: Thu, 31 Mar 2022 18:35:59 +0800 Subject: [PATCH 13/42] feat: configurable app board --- .../components/DashboardFrame/Navigation.tsx | 4 +- .../pages/Wallets/components/Assets/index.tsx | 4 +- .../components/CollectibleCard/index.tsx | 4 +- .../components/CollectibleList/index.tsx | 4 +- .../components/FungibleTokenTable/index.tsx | 4 +- .../FungibleTokenTableRow/index.tsx | 4 +- .../dashboard/src/pages/Wallets/index.tsx | 4 +- packages/mask/shared/helpers/index.ts | 1 + packages/mask/shared/index.ts | 2 +- .../CompositionDialog/PluginEntryRender.tsx | 4 +- .../components/shared/ApplicationBoard.tsx | 447 ++---------------- .../shared/EntrySecondLevelDialog.tsx | 53 --- .../plugins/FindTruman/SNSAdaptor/index.tsx | 23 +- .../FindTruman}/assets/findtruman.png | Bin packages/mask/src/plugins/FindTruman/base.ts | 20 +- packages/mask/src/plugins/Gitcoin/base.ts | 2 + .../plugins/ITO/SNSAdaptor/ClaimAllDialog.tsx | 4 +- .../mask/src/plugins/ITO/SNSAdaptor/index.tsx | 44 ++ .../shared => plugins/ITO}/assets/gift.png | Bin .../shared => plugins/ITO}/assets/token.png | Bin packages/mask/src/plugins/ITO/base.ts | 7 +- .../src/plugins/MaskBox/SNSAdaptor/index.tsx | 30 ++ .../MaskBox}/assets/bridge.png | Bin .../MaskBox}/assets/mask_box.png | Bin packages/mask/src/plugins/NextID/base.ts | 2 + .../plugins/NextID/components/BindPanelUI.tsx | 4 +- .../NextID/components/Tip/TipDialog.tsx | 4 +- .../NextID/components/UnbindPanelUI.tsx | 4 +- .../src/plugins/Pets/SNSAdaptor/index.tsx | 20 + .../Pets}/assets/mintTeam.png | Bin packages/mask/src/plugins/Pets/base.tsx | 10 +- .../SNSAdaptor}/assets/lucky_drop.png | Bin .../plugins/RedPacket/SNSAdaptor/index.tsx | 25 + packages/mask/src/plugins/RedPacket/base.ts | 7 +- .../Savings/SNSAdaptor/SavingsDialog.tsx | 2 +- .../Savings/SNSAdaptor}/assets/savings.png | Bin .../src/plugins/Savings/SNSAdaptor/index.tsx | 22 + packages/mask/src/plugins/Savings/base.ts | 24 +- .../src/plugins/Trader/SNSAdaptor/index.tsx | 20 + .../Trader/SNSAdaptor/trader/TraderDialog.tsx | 4 +- .../shared => plugins/Trader}/assets/swap.png | Bin packages/mask/src/plugins/Trader/base.ts | 2 + .../src/plugins/Transak/SNSAdaptor/index.tsx | 20 + .../Transak}/assets/fiat_ramp.png | Bin .../mask/src/plugins/UnlockProtocol/base.ts | 2 + .../src/web3/UI/EthereumChainBoundary.tsx | 4 +- packages/plugin-infra/src/types.ts | 46 +- packages/plugin-infra/src/web3/Context.tsx | 4 +- .../src/web3/useNetworkDescriptor.ts | 4 +- .../src/web3/useNetworkDescriptors.ts | 4 +- .../src/web3/useProviderDescriptor.ts | 4 +- .../src/web3/useProviderDescriptors.ts | 4 +- .../plugin-infra/src/web3/useWeb3State.ts | 4 +- packages/plugin-infra/src/web3/useWeb3UI.ts | 4 +- .../src/SNSAdaptor/ConnectButton.tsx | 4 +- .../FileService/src/SNSAdaptor/index.tsx | 25 + .../UI/components/ApplicationEntry/index.tsx | 58 +++ packages/shared/src/UI/components/index.ts | 1 + pnpm-lock.yaml | 2 +- 59 files changed, 454 insertions(+), 551 deletions(-) create mode 100644 packages/mask/shared/helpers/index.ts delete mode 100644 packages/mask/src/components/shared/EntrySecondLevelDialog.tsx rename packages/mask/src/{components/shared => plugins/FindTruman}/assets/findtruman.png (100%) rename packages/mask/src/{components/shared => plugins/ITO}/assets/gift.png (100%) rename packages/mask/src/{components/shared => plugins/ITO}/assets/token.png (100%) rename packages/mask/src/{components/shared => plugins/MaskBox}/assets/bridge.png (100%) rename packages/mask/src/{components/shared => plugins/MaskBox}/assets/mask_box.png (100%) rename packages/mask/src/{components/shared => plugins/Pets}/assets/mintTeam.png (100%) rename packages/mask/src/{components/shared => plugins/RedPacket/SNSAdaptor}/assets/lucky_drop.png (100%) rename packages/mask/src/{components/shared => plugins/Savings/SNSAdaptor}/assets/savings.png (100%) rename packages/mask/src/{components/shared => plugins/Trader}/assets/swap.png (100%) rename packages/mask/src/{components/shared => plugins/Transak}/assets/fiat_ramp.png (100%) create mode 100644 packages/shared/src/UI/components/ApplicationEntry/index.tsx diff --git a/packages/dashboard/src/components/DashboardFrame/Navigation.tsx b/packages/dashboard/src/components/DashboardFrame/Navigation.tsx index 196763c73993..469b906b6ac1 100644 --- a/packages/dashboard/src/components/DashboardFrame/Navigation.tsx +++ b/packages/dashboard/src/components/DashboardFrame/Navigation.tsx @@ -32,7 +32,7 @@ import { import { useDashboardI18N } from '../../locales' import { MaskColorVar } from '@masknet/theme' import { DashboardRoutes } from '@masknet/shared-base' -import { NetworkPluginID, usePluginIDContext } from '@masknet/plugin-infra' +import { NetworkPluginID, useCurrentWeb3NetworkPluginID } from '@masknet/plugin-infra' const ListItemLinkUnStyled = ({ to, ...props }: ListItemProps & { to: string }) => { const navigate = useNavigate() @@ -123,7 +123,7 @@ export function Navigation({ onClose }: NavigationProps) { const isLargeScreen = useMediaQuery((theme) => theme.breakpoints.up('lg')) const t = useDashboardI18N() const mode = useTheme().palette.mode - const currentPluginId = usePluginIDContext() + const currentPluginId = useCurrentWeb3NetworkPluginID() const onExpand = (e: React.MouseEvent) => { e.stopPropagation() diff --git a/packages/dashboard/src/pages/Wallets/components/Assets/index.tsx b/packages/dashboard/src/pages/Wallets/components/Assets/index.tsx index 6775727c3f3f..2bb501567f86 100644 --- a/packages/dashboard/src/pages/Wallets/components/Assets/index.tsx +++ b/packages/dashboard/src/pages/Wallets/components/Assets/index.tsx @@ -10,7 +10,7 @@ import { AddCollectibleDialog } from '../AddCollectibleDialog' import { useRemoteControlledDialog } from '@masknet/shared-base-ui' import { PluginMessages } from '../../../../API' import type { Web3Plugin } from '@masknet/plugin-infra' -import { NetworkPluginID, usePluginIDContext } from '@masknet/plugin-infra' +import { NetworkPluginID, useCurrentWeb3NetworkPluginID } from '@masknet/plugin-infra' import { v4 as uuid } from 'uuid' const useStyles = makeStyles()((theme) => ({ @@ -46,7 +46,7 @@ interface TokenAssetsProps { export const Assets = memo(({ network }) => { const t = useDashboardI18N() - const pluginId = usePluginIDContext() + const pluginId = useCurrentWeb3NetworkPluginID() const { classes } = useStyles() const [id] = useState(uuid()) const assetTabsLabel: Record = { diff --git a/packages/dashboard/src/pages/Wallets/components/CollectibleCard/index.tsx b/packages/dashboard/src/pages/Wallets/components/CollectibleCard/index.tsx index 4aabccd9f475..f6efbf2c828a 100644 --- a/packages/dashboard/src/pages/Wallets/components/CollectibleCard/index.tsx +++ b/packages/dashboard/src/pages/Wallets/components/CollectibleCard/index.tsx @@ -9,7 +9,7 @@ import { ChangeNetworkTip } from '../FungibleTokenTableRow/ChangeNetworkTip' import { NetworkPluginID, useNetworkDescriptor, - usePluginIDContext, + useCurrentWeb3NetworkPluginID, useWeb3State, Web3Plugin, } from '@masknet/plugin-infra' @@ -109,7 +109,7 @@ export const CollectibleCard = memo(({ chainId, token, onS const isHovering = useHoverDirty(ref) const networkDescriptor = useNetworkDescriptor(token.contract?.chainId) const isOnCurrentChain = useMemo(() => chainId === token.contract?.chainId, [chainId, token]) - const currentPluginId = usePluginIDContext() + const currentPluginId = useCurrentWeb3NetworkPluginID() useEffect(() => { setHoveringTooltip(false) diff --git a/packages/dashboard/src/pages/Wallets/components/CollectibleList/index.tsx b/packages/dashboard/src/pages/Wallets/components/CollectibleList/index.tsx index 934f6189d4c7..58fae8cd29ef 100644 --- a/packages/dashboard/src/pages/Wallets/components/CollectibleList/index.tsx +++ b/packages/dashboard/src/pages/Wallets/components/CollectibleList/index.tsx @@ -15,7 +15,7 @@ import { useWeb3State as useWeb3PluginState, Web3Plugin, useAccount, - usePluginIDContext, + useCurrentWeb3NetworkPluginID, NetworkPluginID, } from '@masknet/plugin-infra' import { useAsyncRetry } from 'react-use' @@ -72,7 +72,7 @@ export const CollectibleList = memo(({ selectedNetwork }) setRenderData(render) }, [value.data, loadingSize, page]) - const currentPluginId = usePluginIDContext() + const currentPluginId = useCurrentWeb3NetworkPluginID() const onSend = useCallback( (detail: Web3Plugin.NonFungibleToken) => { // Sending NFT is only available on EVM currently. diff --git a/packages/dashboard/src/pages/Wallets/components/FungibleTokenTable/index.tsx b/packages/dashboard/src/pages/Wallets/components/FungibleTokenTable/index.tsx index eab1e788ea4b..5ae01fcc022a 100644 --- a/packages/dashboard/src/pages/Wallets/components/FungibleTokenTable/index.tsx +++ b/packages/dashboard/src/pages/Wallets/components/FungibleTokenTable/index.tsx @@ -18,7 +18,7 @@ import { Web3Plugin, useAccount, NetworkPluginID, - usePluginIDContext, + useCurrentWeb3NetworkPluginID, } from '@masknet/plugin-infra' const useStyles = makeStyles()((theme) => ({ @@ -133,7 +133,7 @@ export interface TokenTableUIProps { export const TokenTableUI = memo(({ onSwap, onSend, isLoading, isEmpty, dataSource }) => { const t = useDashboardI18N() const { classes } = useStyles() - const currentPluginId = usePluginIDContext() + const currentPluginId = useCurrentWeb3NetworkPluginID() const { Utils } = useWeb3PluginState() return ( diff --git a/packages/dashboard/src/pages/Wallets/components/FungibleTokenTableRow/index.tsx b/packages/dashboard/src/pages/Wallets/components/FungibleTokenTableRow/index.tsx index e241e78fb8e2..9f0346e4d371 100644 --- a/packages/dashboard/src/pages/Wallets/components/FungibleTokenTableRow/index.tsx +++ b/packages/dashboard/src/pages/Wallets/components/FungibleTokenTableRow/index.tsx @@ -8,7 +8,7 @@ import { NetworkPluginID, useChainId, useNetworkDescriptors, - usePluginIDContext, + useCurrentWeb3NetworkPluginID, useWeb3State, Web3Plugin, } from '@masknet/plugin-infra' @@ -77,7 +77,7 @@ export const FungibleTokenTableRow = memo(({ asset, onSend, const currentChainId = useChainId() const { Utils } = useWeb3State() const networkDescriptors = useNetworkDescriptors() - const currentPluginId = usePluginIDContext() + const currentPluginId = useCurrentWeb3NetworkPluginID() const isOnCurrentChain = useMemo(() => currentChainId === asset.token.chainId, [asset, currentChainId]) return ( diff --git a/packages/dashboard/src/pages/Wallets/index.tsx b/packages/dashboard/src/pages/Wallets/index.tsx index 51f53c52697a..676c9be0e2e4 100644 --- a/packages/dashboard/src/pages/Wallets/index.tsx +++ b/packages/dashboard/src/pages/Wallets/index.tsx @@ -4,7 +4,7 @@ import { useAccount, useChainId, useNetworkDescriptor, - usePluginIDContext, + useCurrentWeb3NetworkPluginID, useWallet, useWallets, useWeb3State as useWeb3PluginState, @@ -51,7 +51,7 @@ function Wallets() { const networks = getRegisteredWeb3Networks() const networkDescriptor = useNetworkDescriptor() - const pluginId = usePluginIDContext() + const pluginId = useCurrentWeb3NetworkPluginID() const [selectedNetwork, setSelectedNetwork] = useState( networkDescriptor ?? null, ) diff --git a/packages/mask/shared/helpers/index.ts b/packages/mask/shared/helpers/index.ts new file mode 100644 index 000000000000..99d94fcfb3c4 --- /dev/null +++ b/packages/mask/shared/helpers/index.ts @@ -0,0 +1 @@ +export * from './download' diff --git a/packages/mask/shared/index.ts b/packages/mask/shared/index.ts index b02aa56ca45f..1a05d3e0ac64 100644 --- a/packages/mask/shared/index.ts +++ b/packages/mask/shared/index.ts @@ -1,4 +1,4 @@ export * from './messages' export * from './flags' export { InMemoryStorages, PersistentStorages } from './kv-storage' -export * from './helpers/download' +export * from './helpers' diff --git a/packages/mask/src/components/CompositionDialog/PluginEntryRender.tsx b/packages/mask/src/components/CompositionDialog/PluginEntryRender.tsx index 5db488b0ef98..0f24a4afb9ed 100644 --- a/packages/mask/src/components/CompositionDialog/PluginEntryRender.tsx +++ b/packages/mask/src/components/CompositionDialog/PluginEntryRender.tsx @@ -1,5 +1,5 @@ import { - usePluginIDContext, + useCurrentWeb3NetworkPluginID, useActivatedPluginSNSAdaptor_Web3Supported, useActivatedPluginsSNSAdaptor, Plugin, @@ -28,7 +28,7 @@ export const PluginEntryRender = memo( const [trackPluginRef] = useSetPluginEntryRenderRef(ref) const pluginField = usePluginI18NField() const chainId = useChainId() - const pluginID = usePluginIDContext() + const pluginID = useCurrentWeb3NetworkPluginID() const operatingSupportedChainMapping = useActivatedPluginSNSAdaptor_Web3Supported(chainId, pluginID) const result = [...useActivatedPluginsSNSAdaptor('any')] .sort((plugin) => { diff --git a/packages/mask/src/components/shared/ApplicationBoard.tsx b/packages/mask/src/components/shared/ApplicationBoard.tsx index c8bf6fd36f5a..1085906290d5 100644 --- a/packages/mask/src/components/shared/ApplicationBoard.tsx +++ b/packages/mask/src/components/shared/ApplicationBoard.tsx @@ -1,76 +1,14 @@ -import { useCallback, useState } from 'react' -import classNames from 'classnames' -import { Typography } from '@mui/material' +import { Fragment } from 'react' import { makeStyles } from '@masknet/theme' -import { ChainId, useChainId, useAccount, useWallet } from '@masknet/web3-shared-evm' -import { openWindow, useRemoteControlledDialog } from '@masknet/shared-base-ui' -import { CrossIsolationMessages } from '@masknet/shared-base' -import { useControlledDialog } from '../../utils/hooks/useControlledDialog' -import { RedPacketPluginID } from '../../plugins/RedPacket/constants' -import { ITO_PluginID } from '../../plugins/ITO/constants' -import { base as ITO_Definition } from '../../plugins/ITO/base' -import { PluginTransakMessages } from '../../plugins/Transak/messages' -import { PluginPetMessages } from '../../plugins/Pets/messages' -import { ClaimAllDialog } from '../../plugins/ITO/SNSAdaptor/ClaimAllDialog' -import { EntrySecondLevelDialog } from './EntrySecondLevelDialog' -import { NetworkTab } from './NetworkTab' -import { SavingsDialog } from '../../plugins/Savings/SNSAdaptor/SavingsDialog' -import { TraderDialog } from '../../plugins/Trader/SNSAdaptor/trader/TraderDialog' -import { NetworkPluginID, PluginId, usePluginIDContext } from '@masknet/plugin-infra' -import { FindTrumanDialog } from '../../plugins/FindTruman/SNSAdaptor/FindTrumanDialog' -import { isTwitter } from '../../social-network-adaptor/twitter.com/base' +import { useChainId } from '@masknet/web3-shared-evm' +import { useActivatedPluginsSNSAdaptor, useCurrentWeb3NetworkPluginID } from '@masknet/plugin-infra' +import type { Plugin } from '@masknet/plugin-infra' +import { getCurrentSNSNetwork } from '../../social-network-adaptor/utils' import { activatedSocialNetworkUI } from '../../social-network' const useStyles = makeStyles()((theme) => { const smallQuery = `@media (max-width: ${theme.breakpoints.values.sm}px)` return { - abstractTabWrapper: { - position: 'sticky', - top: 0, - width: '100%', - zIndex: 2, - paddingTop: theme.spacing(1), - paddingBottom: theme.spacing(2), - backgroundColor: theme.palette.background.paper, - }, - tab: { - height: 36, - minHeight: 36, - fontWeight: 300, - }, - tabs: { - width: 552, - height: 36, - minHeight: 36, - margin: '0 auto', - borderRadius: 4, - '& .Mui-selected': { - color: theme.palette.primary.contrastText, - backgroundColor: theme.palette.primary.main, - }, - }, - tabPanel: { - marginTop: theme.spacing(3), - }, - indicator: { - display: 'none', - }, - applicationBox: { - display: 'flex', - flexDirection: 'column', - justifyContent: 'center', - alignItems: 'center', - backgroundColor: theme.palette.background.default, - borderRadius: '8px', - cursor: 'pointer', - height: 100, - '@media (hover: hover)': { - '&:hover': { - transform: 'scale(1.05) translateY(-4px)', - boxShadow: theme.palette.mode === 'light' ? '0px 10px 16px rgba(0, 0, 0, 0.1)' : 'none', - }, - }, - }, applicationWrapper: { marginTop: theme.spacing(0.5), display: 'grid', @@ -86,350 +24,55 @@ const useStyles = makeStyles()((theme) => { gridGap: theme.spacing(1), }, }, - applicationImg: { - width: 36, - height: 36, - marginBottom: theme.spacing(1), - }, - disabled: { - pointerEvents: 'none', - opacity: 0.5, - }, - title: { - fontSize: 15, - [smallQuery]: { - fontSize: 13, - }, - }, } }) -const SUPPORTED_CHAIN_ID_LIST = [ - ChainId.Mainnet, - ChainId.BSC, - ChainId.Matic, - ChainId.Arbitrum, - ChainId.xDai, - ChainId.Celo, - ChainId.Fantom, - ChainId.Aurora, - ChainId.Avalanche, -] - -export interface MaskAppEntry { - title: string - img: string - onClick: any - supportedChains?: ChainId[] - hidden: boolean - walletRequired: boolean -} - -interface MaskApplicationBoxProps { - secondEntries?: MaskAppEntry[] - secondEntryChainTabs?: ChainId[] -} - -export function ApplicationBoard({ secondEntries, secondEntryChainTabs }: MaskApplicationBoxProps) { +export function ApplicationBoard() { const { classes } = useStyles() - const currentChainId = useChainId() - const account = useAccount() - const selectedWallet = useWallet() - const currentPluginId = usePluginIDContext() - const isNotEvm = currentPluginId !== NetworkPluginID.PLUGIN_EVM - - // #region Encrypted message - const openEncryptedMessage = useCallback( - (id?: string) => - CrossIsolationMessages.events.requestComposition.sendToLocal({ - reason: 'timeline', - open: true, - options: { - startupPlugin: id, - }, - }), - [], - ) - // #endregion - - // #region Claim All ITO - const { - open: isClaimAllDialogOpen, - onOpen: onClaimAllDialogOpen, - onClose: onClaimAllDialogClose, - } = useControlledDialog() - // #endregion - - // #region Savings - const { - open: isSavingsDialogOpen, - onOpen: onSavingsDialogOpen, - onClose: onSavingsDialogClose, - } = useControlledDialog() - // #endregion - - // #region Swap - const { open: isSwapDialogOpen, onOpen: onSwapDialogOpen, onClose: onSwapDialogClose } = useControlledDialog() - // #endregion - - // #region Fiat on/off ramp - const { setDialog: setBuyDialog } = useRemoteControlledDialog(PluginTransakMessages.buyTokenDialogUpdated) - // #endregion - - // #region pet friends - const { setDialog: setPetDialog } = useRemoteControlledDialog(PluginPetMessages.events.essayDialogUpdated) - // #endregion - - // #region second level entry dialog - const { - open: isSecondLevelEntryDialogOpen, - onOpen: onSecondLevelEntryDialogOpen, - onClose: onSecondLevelEntryDialogClose, - } = useControlledDialog() - - const [secondLevelEntryDialogTitle, setSecondLevelEntryDialogTitle] = useState('') - const [secondLevelEntryChains, setSecondLevelEntryChains] = useState([]) - const [secondLevelEntries, setSecondLevelEntries] = useState([]) - - const [chainId, setChainId] = useState( - secondEntryChainTabs?.includes(currentChainId) ? currentChainId : ChainId.Mainnet, - ) - - const openSecondEntryDir = useCallback( - (title: string, maskAppEntries: MaskAppEntry[], chains: ChainId[] | undefined) => { - setSecondLevelEntryDialogTitle(title) - setSecondLevelEntries(maskAppEntries) - setSecondLevelEntryChains(chains) - onSecondLevelEntryDialogOpen() - }, - [], - ) - // #endregion - - // #region FindTruman - const { - open: isFindTrumanDialogOpen, - onOpen: onFindTrumanDialogOpen, - onClose: onFindTrumanDialogClose, - } = useControlledDialog() - // #endregion - - function createEntry( - title: string, - img: string, - onClick: any, - supportedChains?: ChainId[], - hidden = false, - walletRequired = true, - ) { - return { - title, - img, - onClick, - supportedChains, - hidden, - walletRequired, - } - } - - // Todo: remove this after refactor applicationBoard - const isITOSupportedChain = - ITO_Definition.enableRequirement.web3![currentPluginId]?.supportedChainIds?.includes(currentChainId) - - const firstLevelEntries: MaskAppEntry[] = [ - createEntry( - 'Lucky Drop', - new URL('./assets/lucky_drop.png', import.meta.url).toString(), - () => openEncryptedMessage(RedPacketPluginID), - undefined, - isNotEvm, - ), - createEntry( - 'File Service', - new URL('./assets/files.png', import.meta.url).toString(), - () => openEncryptedMessage(PluginId.FileService), - undefined, - false, - false, - ), - createEntry( - 'ITO', - new URL('./assets/token.png', import.meta.url).toString(), - () => openEncryptedMessage(ITO_PluginID), - undefined, - !isITOSupportedChain, - ), - createEntry( - 'Claim', - new URL('./assets/gift.png', import.meta.url).toString(), - onClaimAllDialogOpen, - undefined, - !isITOSupportedChain, - ), - createEntry( - 'Mask Bridge', - new URL('./assets/bridge.png', import.meta.url).toString(), - () => openWindow('https://bridge.mask.io'), - undefined, - isNotEvm, - false, - ), - createEntry( - 'MaskBox', - new URL('./assets/mask_box.png', import.meta.url).toString(), - () => openWindow('https://box.mask.io'), - undefined, - isNotEvm, - false, - ), - createEntry( - 'Savings', - new URL('./assets/savings.png', import.meta.url).toString(), - onSavingsDialogOpen, - undefined, - isNotEvm, - ), - createEntry( - 'Swap', - new URL('./assets/swap.png', import.meta.url).toString(), - onSwapDialogOpen, - undefined, - isNotEvm || currentChainId === ChainId.Conflux, - ), - createEntry( - 'Fiat On-Ramp', - new URL('./assets/fiat_ramp.png', import.meta.url).toString(), - () => setBuyDialog({ open: true, address: account }), - undefined, - false, - false, - ), - createEntry( - 'NFTs', - new URL('./assets/nft.png', import.meta.url).toString(), - () => - openSecondEntryDir( - 'NFTs', - [ - createEntry( - 'MaskBox', - new URL('./assets/mask_box.png', import.meta.url).toString(), - () => openWindow('https://box.mask.io'), - undefined, - false, - false, - ), - createEntry( - 'Valuables', - new URL('./assets/valuables.png', import.meta.url).toString(), - () => {}, - undefined, - true, - ), - createEntry( - 'Non-F Friends', - new URL('./assets/mintTeam.png', import.meta.url).toString(), - () => setPetDialog({ open: true }), - [ChainId.Mainnet], - currentChainId !== ChainId.Mainnet || !isTwitter(activatedSocialNetworkUI), - true, - ), - ], - undefined, - ), - undefined, - isNotEvm, - ), - createEntry( - 'Investment', - new URL('./assets/investment.png', import.meta.url).toString(), - () => - openSecondEntryDir( - 'Investment', - [ - createEntry('Zerion', new URL('./assets/zerion.png', import.meta.url).toString(), () => {}, [ - ChainId.Mainnet, - ]), - createEntry('dHEDGE', new URL('./assets/dHEDGE.png', import.meta.url).toString(), () => {}), - ], - SUPPORTED_CHAIN_ID_LIST, - ), - undefined, - true, - ), - createEntry( - 'Alternative', - new URL('./assets/more.png', import.meta.url).toString(), - () => - openSecondEntryDir( - 'Alternative', - [ - createEntry( - 'PoolTogether', - new URL('./assets/pool_together.png', import.meta.url).toString(), - () => {}, - ), - ], - SUPPORTED_CHAIN_ID_LIST, - ), - undefined, - true, - ), - createEntry( - 'FindTruman', - new URL('./assets/findtruman.png', import.meta.url).toString(), - onFindTrumanDialogOpen, - [ChainId.Mainnet], - isNotEvm, - true, - ), - ] + const snsAdaptorPlugins = useActivatedPluginsSNSAdaptor('any') + const currentWeb3Network = useCurrentWeb3NetworkPluginID() + const chainId = useChainId() + const currentSNSNetwork = getCurrentSNSNetwork(activatedSocialNetworkUI.networkIdentifier) return ( <> - {secondEntryChainTabs?.length ? ( -
- -
- ) : null}
- {(secondEntries ?? firstLevelEntries).map( - ({ title, img, onClick, supportedChains, hidden, walletRequired }, i) => - (!supportedChains || supportedChains?.includes(chainId)) && !hidden ? ( -
- - - {title} - -
- ) : null, - )} + {snsAdaptorPlugins + .reduce<{ entry: Plugin.SNSAdaptor.ApplicationEntry; enabled: boolean; pluginId: string }[]>( + (acc, cur) => { + if (!cur.ApplicationEntries) return acc + const currentWeb3NetworkSupportedChainIds = cur.enableRequirement.web3?.[currentWeb3Network] + const isWeb3Enabled = Boolean( + currentWeb3NetworkSupportedChainIds === undefined || + currentWeb3NetworkSupportedChainIds.supportedChainIds?.includes(chainId), + ) + + const currentSNSIsSupportedNetwork = + cur.enableRequirement.networks.networks[currentSNSNetwork] + const isSNSEnabled = + currentSNSIsSupportedNetwork === undefined || currentSNSIsSupportedNetwork + + return acc.concat( + cur.ApplicationEntries.map((x) => { + return { + entry: x, + enabled: isWeb3Enabled && isSNSEnabled, + pluginId: cur.ID, + } + }) ?? [], + ) + }, + [], + ) + .sort((a, b) => a.entry.defaultSortingPriority - b.entry.defaultSortingPriority) + .map((X, i) => { + return ( + + + + ) + })}
- {isClaimAllDialogOpen ? : null} - {isSecondLevelEntryDialogOpen ? ( - - ) : null} - {isFindTrumanDialogOpen ? : null} - {isSwapDialogOpen ? : null} - - {isSavingsDialogOpen ? : null} ) } diff --git a/packages/mask/src/components/shared/EntrySecondLevelDialog.tsx b/packages/mask/src/components/shared/EntrySecondLevelDialog.tsx deleted file mode 100644 index 3eaa28361d04..000000000000 --- a/packages/mask/src/components/shared/EntrySecondLevelDialog.tsx +++ /dev/null @@ -1,53 +0,0 @@ -import { DialogContent } from '@mui/material' -import { makeStyles } from '@masknet/theme' -import { InjectedDialog } from './InjectedDialog' -import { WalletStatusBox } from './WalletStatusBox' -import { ApplicationBoard, MaskAppEntry } from './ApplicationBoard' -import type { ChainId } from '@masknet/web3-shared-evm' - -const useStyles = makeStyles()((theme) => ({ - content: { - padding: theme.spacing(2, 3, 3), - minHeight: 491, - }, - footer: { - fontSize: 12, - textAlign: 'left', - padding: theme.spacing(2), - borderTop: `1px solid ${theme.palette.divider}`, - justifyContent: 'flex-start', - }, - address: { - fontSize: 16, - marginRight: theme.spacing(1), - display: 'inline-block', - }, - subTitle: { - fontSize: 18, - lineHeight: '24px', - fontWeight: 600, - marginBottom: 11.5, - color: theme.palette.text.primary, - }, -})) - -interface EntrySecondLevelDialogProps { - title: string - entries?: MaskAppEntry[] - chains?: ChainId[] - open: boolean - closeDialog: () => void -} - -export function EntrySecondLevelDialog(props: EntrySecondLevelDialogProps) { - const { classes } = useStyles() - - return ( - - - - - - - ) -} diff --git a/packages/mask/src/plugins/FindTruman/SNSAdaptor/index.tsx b/packages/mask/src/plugins/FindTruman/SNSAdaptor/index.tsx index 93b229a4f97e..5c9c787ce528 100644 --- a/packages/mask/src/plugins/FindTruman/SNSAdaptor/index.tsx +++ b/packages/mask/src/plugins/FindTruman/SNSAdaptor/index.tsx @@ -1,11 +1,13 @@ import { base } from '../base' -import { useMemo, Suspense } from 'react' +import { useMemo, Suspense, useState } from 'react' import { Skeleton } from '@mui/material' import { makeStyles } from '@masknet/theme' import { type Plugin, usePostInfoDetails, usePluginWrapper } from '@masknet/plugin-infra' import { extractTextFromTypedMessage } from '@masknet/typed-message' import { parseURL } from '@masknet/shared-base' import { PostInspector } from './PostInspector' +import { ApplicationEntry } from '@masknet/shared' +import { FindTrumanDialog } from './FindTrumanDialog' const useStyles = makeStyles()((theme) => { return { @@ -84,6 +86,25 @@ const sns: Plugin.SNSAdaptor.Definition = { if (!link) return null return }, + ApplicationEntries: [ + { + RenderEntryComponent({ disabled }) { + const [open, setOpen] = useState(false) + return ( + <> + setOpen(true)} + /> + setOpen(false)} /> + + ) + }, + defaultSortingPriority: 11, + }, + ], } export default sns diff --git a/packages/mask/src/components/shared/assets/findtruman.png b/packages/mask/src/plugins/FindTruman/assets/findtruman.png similarity index 100% rename from packages/mask/src/components/shared/assets/findtruman.png rename to packages/mask/src/plugins/FindTruman/assets/findtruman.png diff --git a/packages/mask/src/plugins/FindTruman/base.ts b/packages/mask/src/plugins/FindTruman/base.ts index 8b9bb909e652..8ded5d9bb91f 100644 --- a/packages/mask/src/plugins/FindTruman/base.ts +++ b/packages/mask/src/plugins/FindTruman/base.ts @@ -1,4 +1,5 @@ -import type { Plugin } from '@masknet/plugin-infra' +import { Plugin, NetworkPluginID } from '@masknet/plugin-infra' +import { ChainId } from '@masknet/web3-shared-evm' import { FIND_TRUMAN_PLUGIN_ID, FIND_TRUMAN_PLUGIN_NAME } from './constants' export const base: Plugin.Shared.Definition = { @@ -13,6 +14,23 @@ export const base: Plugin.Shared.Definition = { architecture: { app: true, web: true }, networks: { type: 'opt-out', networks: {} }, target: 'stable', + web3: { + [NetworkPluginID.PLUGIN_EVM]: { + supportedChainIds: [ + ChainId.Mainnet, + ChainId.BSC, + ChainId.Matic, + ChainId.Arbitrum, + ChainId.xDai, + ChainId.Fantom, + ChainId.Avalanche, + ChainId.Aurora, + ChainId.Conflux, + ], + }, + [NetworkPluginID.PLUGIN_FLOW]: { supportedChainIds: [] }, + [NetworkPluginID.PLUGIN_SOLANA]: { supportedChainIds: [] }, + }, }, contribution: { postContent: new Set([ diff --git a/packages/mask/src/plugins/Gitcoin/base.ts b/packages/mask/src/plugins/Gitcoin/base.ts index 351f388d12bd..e3387df5a855 100644 --- a/packages/mask/src/plugins/Gitcoin/base.ts +++ b/packages/mask/src/plugins/Gitcoin/base.ts @@ -16,6 +16,8 @@ export const base: Plugin.Shared.Definition = { [NetworkPluginID.PLUGIN_EVM]: { supportedChainIds: [ChainId.Mainnet, ChainId.Rinkeby, ChainId.Matic, ChainId.Mumbai], }, + [NetworkPluginID.PLUGIN_FLOW]: { supportedChainIds: [] }, + [NetworkPluginID.PLUGIN_SOLANA]: { supportedChainIds: [] }, }, }, contribution: { postContent: new Set([/https:\/\/gitcoin.co\/grants\/\d+/]) }, diff --git a/packages/mask/src/plugins/ITO/SNSAdaptor/ClaimAllDialog.tsx b/packages/mask/src/plugins/ITO/SNSAdaptor/ClaimAllDialog.tsx index 499ae2566b3b..cf8f32f94a2a 100644 --- a/packages/mask/src/plugins/ITO/SNSAdaptor/ClaimAllDialog.tsx +++ b/packages/mask/src/plugins/ITO/SNSAdaptor/ClaimAllDialog.tsx @@ -1,4 +1,4 @@ -import { usePluginIDContext, PluginId, useActivatedPlugin } from '@masknet/plugin-infra' +import { useCurrentWeb3NetworkPluginID, PluginId, useActivatedPlugin } from '@masknet/plugin-infra' import { useCallback, useEffect, useState, useLayoutEffect, useRef } from 'react' import { flatten, uniq } from 'lodash-unified' import formatDateTime from 'date-fns/format' @@ -230,7 +230,7 @@ export function ClaimAllDialog(props: ClaimAllDialogProps) { const { t } = useI18N() const { open, onClose } = props const ITO_Definition = useActivatedPlugin(PluginId.ITO, 'any') - const pluginId = usePluginIDContext() + const pluginId = useCurrentWeb3NetworkPluginID() const chainIdList = ITO_Definition?.enableRequirement.web3?.[pluginId]?.supportedChainIds ?? [] const DialogRef = useRef(null) const account = useAccount() diff --git a/packages/mask/src/plugins/ITO/SNSAdaptor/index.tsx b/packages/mask/src/plugins/ITO/SNSAdaptor/index.tsx index a1e82a69ff96..d88bf44cac20 100644 --- a/packages/mask/src/plugins/ITO/SNSAdaptor/index.tsx +++ b/packages/mask/src/plugins/ITO/SNSAdaptor/index.tsx @@ -1,4 +1,5 @@ import { Plugin, usePluginWrapper } from '@masknet/plugin-infra' +import { useState } from 'react' import { ItoLabelIcon } from '../assets/ItoLabelIcon' import { makeStyles } from '@masknet/theme' import { @@ -16,6 +17,9 @@ import { CompositionDialog } from './CompositionDialog' import { set } from 'lodash-unified' import { EthereumChainBoundary } from '../../../web3/UI/EthereumChainBoundary' import { MarketsIcon } from '@masknet/icons' +import { ApplicationEntry } from '@masknet/shared' +import { CrossIsolationMessages } from '@masknet/shared-base' +import { ClaimAllDialog } from './ClaimAllDialog' const useStyles = makeStyles()((theme) => ({ root: { @@ -57,6 +61,46 @@ const sns: Plugin.SNSAdaptor.Definition = { ), }, }, + ApplicationEntries: [ + { + RenderEntryComponent({ disabled }) { + return ( + + CrossIsolationMessages.events.requestComposition.sendToLocal({ + reason: 'timeline', + open: true, + options: { + startupPlugin: base.ID, + }, + }) + } + /> + ) + }, + defaultSortingPriority: 3, + }, + { + RenderEntryComponent({ disabled }) { + const [open, setOpen] = useState(false) + return ( + <> + setOpen(true)} + /> + setOpen(false)} /> + + ) + }, + defaultSortingPriority: 4, + }, + ], } function onAttached_ITO(payload: JSON_PayloadComposeMask) { diff --git a/packages/mask/src/components/shared/assets/gift.png b/packages/mask/src/plugins/ITO/assets/gift.png similarity index 100% rename from packages/mask/src/components/shared/assets/gift.png rename to packages/mask/src/plugins/ITO/assets/gift.png diff --git a/packages/mask/src/components/shared/assets/token.png b/packages/mask/src/plugins/ITO/assets/token.png similarity index 100% rename from packages/mask/src/components/shared/assets/token.png rename to packages/mask/src/plugins/ITO/assets/token.png diff --git a/packages/mask/src/plugins/ITO/base.ts b/packages/mask/src/plugins/ITO/base.ts index eceee4b13b46..272f230febbc 100644 --- a/packages/mask/src/plugins/ITO/base.ts +++ b/packages/mask/src/plugins/ITO/base.ts @@ -12,7 +12,10 @@ export const base: Plugin.Shared.Definition = { publisher: { name: { fallback: 'Mask Network' }, link: 'https://mask.io/' }, enableRequirement: { architecture: { app: true, web: true }, - networks: { type: 'opt-out', networks: {} }, + networks: { + type: 'opt-out', + networks: {}, + }, target: 'stable', web3: { [NetworkPluginID.PLUGIN_EVM]: { @@ -27,6 +30,8 @@ export const base: Plugin.Shared.Definition = { ChainId.Fantom, ], }, + [NetworkPluginID.PLUGIN_FLOW]: { supportedChainIds: [] }, + [NetworkPluginID.PLUGIN_SOLANA]: { supportedChainIds: [] }, }, }, contribution: { metadataKeys: new Set([ITO_MetaKey_1, ITO_MetaKey_2]) }, diff --git a/packages/mask/src/plugins/MaskBox/SNSAdaptor/index.tsx b/packages/mask/src/plugins/MaskBox/SNSAdaptor/index.tsx index 7fa3108da7bb..52c5b95dbfee 100644 --- a/packages/mask/src/plugins/MaskBox/SNSAdaptor/index.tsx +++ b/packages/mask/src/plugins/MaskBox/SNSAdaptor/index.tsx @@ -6,6 +6,8 @@ import { parseURL } from '@masknet/shared-base' import { EthereumChainBoundary } from '../../../web3/UI/EthereumChainBoundary' import { PreviewCard } from './components/PreviewCard' import { Context } from '../hooks/useContext' +import { ApplicationEntry } from '@masknet/shared' +import { openWindow } from '@masknet/shared-base-ui' const isMaskBox = (x: string) => x.startsWith('https://box-beta.mask.io') || x.startsWith('https://box.mask.io') @@ -26,6 +28,34 @@ const sns: Plugin.SNSAdaptor.Definition = { if (!link) return null return }, + ApplicationEntries: [ + { + RenderEntryComponent({ disabled }) { + return ( + openWindow('https://bridge.mask.io/#/')} + /> + ) + }, + defaultSortingPriority: 5, + }, + { + RenderEntryComponent({ disabled }) { + return ( + openWindow('https://box.mask.io/#/')} + /> + ) + }, + defaultSortingPriority: 6, + }, + ], } export default sns diff --git a/packages/mask/src/components/shared/assets/bridge.png b/packages/mask/src/plugins/MaskBox/assets/bridge.png similarity index 100% rename from packages/mask/src/components/shared/assets/bridge.png rename to packages/mask/src/plugins/MaskBox/assets/bridge.png diff --git a/packages/mask/src/components/shared/assets/mask_box.png b/packages/mask/src/plugins/MaskBox/assets/mask_box.png similarity index 100% rename from packages/mask/src/components/shared/assets/mask_box.png rename to packages/mask/src/plugins/MaskBox/assets/mask_box.png diff --git a/packages/mask/src/plugins/NextID/base.ts b/packages/mask/src/plugins/NextID/base.ts index 14d2791bcfce..832aeb38641c 100644 --- a/packages/mask/src/plugins/NextID/base.ts +++ b/packages/mask/src/plugins/NextID/base.ts @@ -31,6 +31,8 @@ export const base: Plugin.Shared.Definition = { ChainId.Conflux, ], }, + [NetworkPluginID.PLUGIN_FLOW]: { supportedChainIds: [] }, + [NetworkPluginID.PLUGIN_SOLANA]: { supportedChainIds: [] }, }, }, experimentalMark: true, diff --git a/packages/mask/src/plugins/NextID/components/BindPanelUI.tsx b/packages/mask/src/plugins/NextID/components/BindPanelUI.tsx index 56e9cbe617c2..b146fb5fea1e 100644 --- a/packages/mask/src/plugins/NextID/components/BindPanelUI.tsx +++ b/packages/mask/src/plugins/NextID/components/BindPanelUI.tsx @@ -9,7 +9,7 @@ import { getMaskColor, makeStyles, MaskColorVar } from '@masknet/theme' import type { Persona } from '../../../database' import { formatFingerprint, LoadingAnimation } from '@masknet/shared' import { InjectedDialog } from '../../../components/shared/InjectedDialog' -import { NetworkPluginID, usePluginIDContext } from '@masknet/plugin-infra' +import { NetworkPluginID, useCurrentWeb3NetworkPluginID } from '@masknet/plugin-infra' const useStyles = makeStyles()((theme) => ({ persona: { @@ -93,7 +93,7 @@ export const BindPanelUI = memo( ({ onPersonaSign, onWalletSign, currentPersona, signature, isBound, title, onClose, open, isCurrentAccount }) => { const t = useI18N() const { classes } = useStyles() - const pluginId = usePluginIDContext() + const pluginId = useCurrentWeb3NetworkPluginID() const isSupported = SUPPORTED_PLUGINS.includes(pluginId) const isWalletSigned = !!signature.wallet.value diff --git a/packages/mask/src/plugins/NextID/components/Tip/TipDialog.tsx b/packages/mask/src/plugins/NextID/components/Tip/TipDialog.tsx index b48584490c84..381beda5be2c 100644 --- a/packages/mask/src/plugins/NextID/components/Tip/TipDialog.tsx +++ b/packages/mask/src/plugins/NextID/components/Tip/TipDialog.tsx @@ -1,5 +1,5 @@ import { SuccessIcon } from '@masknet/icons' -import { PluginId, useActivatedPlugin, usePluginIDContext } from '@masknet/plugin-infra' +import { PluginId, useActivatedPlugin, useCurrentWeb3NetworkPluginID } from '@masknet/plugin-infra' import { NFTCardStyledAssetPlayer } from '@masknet/shared' import { openWindow } from '@masknet/shared-base-ui' import { makeStyles } from '@masknet/theme' @@ -77,7 +77,7 @@ interface TipDialogProps { } export function TipDialog({ open = false, onClose }: TipDialogProps) { - const pluginID = usePluginIDContext() + const pluginID = useCurrentWeb3NetworkPluginID() const tipDefinition = useActivatedPlugin(PluginId.NextID, 'any') const chainIdList = tipDefinition?.enableRequirement.web3?.[pluginID]?.supportedChainIds ?? EMPTY_LIST const t = useI18N() diff --git a/packages/mask/src/plugins/NextID/components/UnbindPanelUI.tsx b/packages/mask/src/plugins/NextID/components/UnbindPanelUI.tsx index 7743ada26936..0b16db064a83 100644 --- a/packages/mask/src/plugins/NextID/components/UnbindPanelUI.tsx +++ b/packages/mask/src/plugins/NextID/components/UnbindPanelUI.tsx @@ -9,7 +9,7 @@ import { getMaskColor, makeStyles, MaskColorVar } from '@masknet/theme' import type { Persona } from '../../../database' import { formatFingerprint, LoadingAnimation } from '@masknet/shared' import { InjectedDialog } from '../../../components/shared/InjectedDialog' -import { NetworkPluginID, usePluginIDContext } from '@masknet/plugin-infra' +import { NetworkPluginID, useCurrentWeb3NetworkPluginID } from '@masknet/plugin-infra' import AbstractTab, { AbstractTabProps } from '../../../components/shared/AbstractTab' const useStyles = makeStyles()((theme) => ({ @@ -95,7 +95,7 @@ export const UnbindPanelUI = memo( ({ onPersonaSign, onWalletSign, currentPersona, signature, isBound, title, onClose, open, isCurrentAccount }) => { const t = useI18N() const { classes } = useStyles() - const pluginId = usePluginIDContext() + const pluginId = useCurrentWeb3NetworkPluginID() const isSupported = SUPPORTED_PLUGINS.includes(pluginId) const isWalletSigned = !!signature.wallet.value diff --git a/packages/mask/src/plugins/Pets/SNSAdaptor/index.tsx b/packages/mask/src/plugins/Pets/SNSAdaptor/index.tsx index 9c3e1ca4d06e..b8e87d5b6bf3 100644 --- a/packages/mask/src/plugins/Pets/SNSAdaptor/index.tsx +++ b/packages/mask/src/plugins/Pets/SNSAdaptor/index.tsx @@ -2,6 +2,9 @@ import type { Plugin } from '@masknet/plugin-infra' import { base } from '../base' import AnimatePic from './Animate' import { PetDialog } from './PetDialog' +import { PluginPetMessages } from '../messages' +import { useRemoteControlledDialog } from '@masknet/shared-base-ui' +import { ApplicationEntry } from '@masknet/shared' const sns: Plugin.SNSAdaptor.Definition = { ...base, @@ -14,6 +17,23 @@ const sns: Plugin.SNSAdaptor.Definition = { ) }, + ApplicationEntries: [ + { + RenderEntryComponent({ disabled }) { + const { openDialog } = useRemoteControlledDialog(PluginPetMessages.events.essayDialogUpdated) + + return ( + + ) + }, + defaultSortingPriority: 10, + }, + ], } export default sns diff --git a/packages/mask/src/components/shared/assets/mintTeam.png b/packages/mask/src/plugins/Pets/assets/mintTeam.png similarity index 100% rename from packages/mask/src/components/shared/assets/mintTeam.png rename to packages/mask/src/plugins/Pets/assets/mintTeam.png diff --git a/packages/mask/src/plugins/Pets/base.tsx b/packages/mask/src/plugins/Pets/base.tsx index 119d8bf64690..903598b14901 100644 --- a/packages/mask/src/plugins/Pets/base.tsx +++ b/packages/mask/src/plugins/Pets/base.tsx @@ -1,4 +1,5 @@ -import { CurrentSNSNetwork, Plugin } from '@masknet/plugin-infra' +import { CurrentSNSNetwork, Plugin, NetworkPluginID } from '@masknet/plugin-infra' +import { ChainId } from '@masknet/web3-shared-evm' import { PetsPluginID } from './constants' import { PETSIcon } from '../../resources/PETSIcon' @@ -13,6 +14,13 @@ export const base: Plugin.Shared.Definition = { enableRequirement: { architecture: { app: false, web: true }, networks: { type: 'opt-in', networks: { [CurrentSNSNetwork.Twitter]: true } }, + web3: { + [NetworkPluginID.PLUGIN_EVM]: { + supportedChainIds: [ChainId.Mainnet], + }, + [NetworkPluginID.PLUGIN_FLOW]: { supportedChainIds: [] }, + [NetworkPluginID.PLUGIN_SOLANA]: { supportedChainIds: [] }, + }, target: 'stable', }, } diff --git a/packages/mask/src/components/shared/assets/lucky_drop.png b/packages/mask/src/plugins/RedPacket/SNSAdaptor/assets/lucky_drop.png similarity index 100% rename from packages/mask/src/components/shared/assets/lucky_drop.png rename to packages/mask/src/plugins/RedPacket/SNSAdaptor/assets/lucky_drop.png diff --git a/packages/mask/src/plugins/RedPacket/SNSAdaptor/index.tsx b/packages/mask/src/plugins/RedPacket/SNSAdaptor/index.tsx index 3b60fb8794f0..e8e633e2390e 100644 --- a/packages/mask/src/plugins/RedPacket/SNSAdaptor/index.tsx +++ b/packages/mask/src/plugins/RedPacket/SNSAdaptor/index.tsx @@ -20,6 +20,8 @@ import RedPacketDialog from './RedPacketDialog' import { RedPacketInPost } from './RedPacketInPost' import { RedPacketNftInPost } from './RedPacketNftInPost' import { RedPacketIcon, NFTRedPacketIcon } from '@masknet/icons' +import { CrossIsolationMessages } from '@masknet/shared-base' +import { ApplicationEntry } from '@masknet/shared' function Render(props: React.PropsWithChildren<{ name: string }>) { usePluginWrapper(true, { name: props.name }) @@ -90,6 +92,29 @@ const sns: Plugin.SNSAdaptor.Definition = { ), }, }, + ApplicationEntries: [ + { + RenderEntryComponent({ disabled }) { + return ( + + CrossIsolationMessages.events.requestComposition.sendToLocal({ + reason: 'timeline', + open: true, + options: { + startupPlugin: base.ID, + }, + }) + } + /> + ) + }, + defaultSortingPriority: 1, + }, + ], } interface ERC20RedpacketBadgeProps { payload: RedPacketJSONPayload diff --git a/packages/mask/src/plugins/RedPacket/base.ts b/packages/mask/src/plugins/RedPacket/base.ts index 25fc85ada510..c7d4bfa4c6c5 100644 --- a/packages/mask/src/plugins/RedPacket/base.ts +++ b/packages/mask/src/plugins/RedPacket/base.ts @@ -13,7 +13,10 @@ export const base: Plugin.Shared.Definition = { publisher: { name: { fallback: 'Mask Network' }, link: 'https://mask.io/' }, enableRequirement: { architecture: { app: true, web: true }, - networks: { type: 'opt-out', networks: {} }, + networks: { + type: 'opt-out', + networks: {}, + }, target: 'stable', web3: { [NetworkPluginID.PLUGIN_EVM]: { @@ -29,6 +32,8 @@ export const base: Plugin.Shared.Definition = { ChainId.Conflux, ], }, + [NetworkPluginID.PLUGIN_FLOW]: { supportedChainIds: [] }, + [NetworkPluginID.PLUGIN_SOLANA]: { supportedChainIds: [] }, }, }, contribution: { diff --git a/packages/mask/src/plugins/Savings/SNSAdaptor/SavingsDialog.tsx b/packages/mask/src/plugins/Savings/SNSAdaptor/SavingsDialog.tsx index dfa2dd5b16be..0a521b51376a 100644 --- a/packages/mask/src/plugins/Savings/SNSAdaptor/SavingsDialog.tsx +++ b/packages/mask/src/plugins/Savings/SNSAdaptor/SavingsDialog.tsx @@ -58,7 +58,7 @@ export function SavingsDialog({ open, onClose }: SavingsDialogProps) { { if (selectedProtocol === null) { onClose?.() diff --git a/packages/mask/src/components/shared/assets/savings.png b/packages/mask/src/plugins/Savings/SNSAdaptor/assets/savings.png similarity index 100% rename from packages/mask/src/components/shared/assets/savings.png rename to packages/mask/src/plugins/Savings/SNSAdaptor/assets/savings.png diff --git a/packages/mask/src/plugins/Savings/SNSAdaptor/index.tsx b/packages/mask/src/plugins/Savings/SNSAdaptor/index.tsx index cbabb7a159eb..500c25fb60b7 100644 --- a/packages/mask/src/plugins/Savings/SNSAdaptor/index.tsx +++ b/packages/mask/src/plugins/Savings/SNSAdaptor/index.tsx @@ -1,9 +1,31 @@ import type { Plugin } from '@masknet/plugin-infra' +import { ApplicationEntry } from '@masknet/shared' +import { useState } from 'react' import { base } from '../base' +import { SavingsDialog } from './SavingsDialog' const sns: Plugin.SNSAdaptor.Definition = { ...base, init(signal) {}, + ApplicationEntries: [ + { + RenderEntryComponent({ disabled }) { + const [open, setOpen] = useState(false) + return ( + <> + setOpen(true)} + /> + setOpen(false)} /> + + ) + }, + defaultSortingPriority: 7, + }, + ], } export default sns diff --git a/packages/mask/src/plugins/Savings/base.ts b/packages/mask/src/plugins/Savings/base.ts index 8dc78be6713d..9133a1f2b61e 100644 --- a/packages/mask/src/plugins/Savings/base.ts +++ b/packages/mask/src/plugins/Savings/base.ts @@ -1,4 +1,5 @@ -import type { Plugin } from '@masknet/plugin-infra' +import { Plugin, NetworkPluginID } from '@masknet/plugin-infra' +import { ChainId } from '@masknet/web3-shared-evm' import { SAVINGS_PLUGIN_ID } from './constants' export const base: Plugin.Shared.Definition = { @@ -11,7 +12,26 @@ export const base: Plugin.Shared.Definition = { publisher: { name: { fallback: 'Mask Network' }, link: 'https://mask.io/' }, enableRequirement: { architecture: { app: true, web: true }, - networks: { type: 'opt-out', networks: {} }, + networks: { + type: 'opt-out', + networks: {}, + }, target: 'stable', + web3: { + [NetworkPluginID.PLUGIN_EVM]: { + supportedChainIds: [ + ChainId.Mainnet, + ChainId.BSC, + ChainId.Matic, + ChainId.Arbitrum, + ChainId.xDai, + ChainId.Aurora, + ChainId.Avalanche, + ChainId.Fantom, + ], + }, + [NetworkPluginID.PLUGIN_FLOW]: { supportedChainIds: [] }, + [NetworkPluginID.PLUGIN_SOLANA]: { supportedChainIds: [] }, + }, }, } diff --git a/packages/mask/src/plugins/Trader/SNSAdaptor/index.tsx b/packages/mask/src/plugins/Trader/SNSAdaptor/index.tsx index 29c369c34569..170cab6a531c 100644 --- a/packages/mask/src/plugins/Trader/SNSAdaptor/index.tsx +++ b/packages/mask/src/plugins/Trader/SNSAdaptor/index.tsx @@ -2,8 +2,11 @@ import type { Plugin } from '@masknet/plugin-infra' import { base } from '../base' import { TraderDialog } from './trader/TraderDialog' import { SearchResultInspector } from './trending/SearchResultInspector' +import { useRemoteControlledDialog } from '@masknet/shared-base-ui' import { TagInspector } from './trending/TagInspector' import { enhanceTag } from './cashTag' +import { ApplicationEntry } from '@masknet/shared' +import { PluginTraderMessages } from '../messages' const sns: Plugin.SNSAdaptor.Definition = { ...base, @@ -18,6 +21,23 @@ const sns: Plugin.SNSAdaptor.Definition = { ) }, enhanceTag, + ApplicationEntries: [ + { + RenderEntryComponent({ disabled }) { + const { openDialog } = useRemoteControlledDialog(PluginTraderMessages.swapDialogUpdated) + + return ( + + ) + }, + defaultSortingPriority: 8, + }, + ], } export default sns diff --git a/packages/mask/src/plugins/Trader/SNSAdaptor/trader/TraderDialog.tsx b/packages/mask/src/plugins/Trader/SNSAdaptor/trader/TraderDialog.tsx index 9abcfc2213ae..b8bc3821cdd8 100644 --- a/packages/mask/src/plugins/Trader/SNSAdaptor/trader/TraderDialog.tsx +++ b/packages/mask/src/plugins/Trader/SNSAdaptor/trader/TraderDialog.tsx @@ -1,5 +1,5 @@ import { useEffect, useState } from 'react' -import { usePluginIDContext, useActivatedPlugin, PluginId } from '@masknet/plugin-infra' +import { useCurrentWeb3NetworkPluginID, useActivatedPlugin, PluginId } from '@masknet/plugin-infra' import { ChainId, useChainId, useChainIdValid } from '@masknet/web3-shared-evm' import { DialogContent } from '@mui/material' import { InjectedDialog } from '../../../../components/shared/InjectedDialog' @@ -64,7 +64,7 @@ interface TraderDialogProps { export function TraderDialog({ open, onClose }: TraderDialogProps) { const isDashboard = isDashboardPage() - const pluginID = usePluginIDContext() + const pluginID = useCurrentWeb3NetworkPluginID() const traderDefinition = useActivatedPlugin(PluginId.Trader, 'any') const chainIdList = traderDefinition?.enableRequirement.web3?.[pluginID]?.supportedChainIds ?? [] const { t } = useI18N() diff --git a/packages/mask/src/components/shared/assets/swap.png b/packages/mask/src/plugins/Trader/assets/swap.png similarity index 100% rename from packages/mask/src/components/shared/assets/swap.png rename to packages/mask/src/plugins/Trader/assets/swap.png diff --git a/packages/mask/src/plugins/Trader/base.ts b/packages/mask/src/plugins/Trader/base.ts index 2c575a7ae707..389413f09230 100644 --- a/packages/mask/src/plugins/Trader/base.ts +++ b/packages/mask/src/plugins/Trader/base.ts @@ -25,6 +25,8 @@ export const base: Plugin.Shared.Definition = { ChainId.Fantom, ], }, + [NetworkPluginID.PLUGIN_FLOW]: { supportedChainIds: [] }, + [NetworkPluginID.PLUGIN_SOLANA]: { supportedChainIds: [] }, }, }, } diff --git a/packages/mask/src/plugins/Transak/SNSAdaptor/index.tsx b/packages/mask/src/plugins/Transak/SNSAdaptor/index.tsx index cd1bec646b9d..2a0d7d219a3b 100644 --- a/packages/mask/src/plugins/Transak/SNSAdaptor/index.tsx +++ b/packages/mask/src/plugins/Transak/SNSAdaptor/index.tsx @@ -1,6 +1,9 @@ import type { Plugin } from '@masknet/plugin-infra' import { base } from '../base' import { BuyTokenDialog } from './BuyTokenDialog' +import { PluginTransakMessages } from '../messages' +import { useRemoteControlledDialog } from '@masknet/shared-base-ui' +import { ApplicationEntry } from '@masknet/shared' const sns: Plugin.SNSAdaptor.Definition = { ...base, @@ -8,6 +11,23 @@ const sns: Plugin.SNSAdaptor.Definition = { GlobalInjection() { return }, + ApplicationEntries: [ + { + RenderEntryComponent({ disabled }) { + const { openDialog } = useRemoteControlledDialog(PluginTransakMessages.buyTokenDialogUpdated) + + return ( + + ) + }, + defaultSortingPriority: 9, + }, + ], } export default sns diff --git a/packages/mask/src/components/shared/assets/fiat_ramp.png b/packages/mask/src/plugins/Transak/assets/fiat_ramp.png similarity index 100% rename from packages/mask/src/components/shared/assets/fiat_ramp.png rename to packages/mask/src/plugins/Transak/assets/fiat_ramp.png diff --git a/packages/mask/src/plugins/UnlockProtocol/base.ts b/packages/mask/src/plugins/UnlockProtocol/base.ts index b6be16f2bda6..7b29c145ed32 100644 --- a/packages/mask/src/plugins/UnlockProtocol/base.ts +++ b/packages/mask/src/plugins/UnlockProtocol/base.ts @@ -16,6 +16,8 @@ export const base: Plugin.Shared.Definition = { [NetworkPluginID.PLUGIN_EVM]: { supportedChainIds: [ChainId.Mainnet, ChainId.xDai, ChainId.Matic, ChainId.Rinkeby], }, + [NetworkPluginID.PLUGIN_FLOW]: { supportedChainIds: [] }, + [NetworkPluginID.PLUGIN_SOLANA]: { supportedChainIds: [] }, }, }, contribution: { diff --git a/packages/mask/src/web3/UI/EthereumChainBoundary.tsx b/packages/mask/src/web3/UI/EthereumChainBoundary.tsx index 91ed0bb4a016..ae7288a76a70 100644 --- a/packages/mask/src/web3/UI/EthereumChainBoundary.tsx +++ b/packages/mask/src/web3/UI/EthereumChainBoundary.tsx @@ -2,7 +2,7 @@ import React, { useCallback } from 'react' import { Box, Typography, Theme } from '@mui/material' import { makeStyles, useStylesExtends } from '@masknet/theme' import type { SxProps } from '@mui/system' -import { NetworkPluginID, useActivatedPlugin, usePluginIDContext, useAccount } from '@masknet/plugin-infra' +import { NetworkPluginID, useActivatedPlugin, useCurrentWeb3NetworkPluginID, useAccount } from '@masknet/plugin-infra' import { ChainId, getChainDetailedCAIP, @@ -45,7 +45,7 @@ export interface EthereumChainBoundaryProps extends withClasses<'switchButton'> export function EthereumChainBoundary(props: EthereumChainBoundaryProps) { const { t } = useI18N() - const pluginID = usePluginIDContext() + const pluginID = useCurrentWeb3NetworkPluginID() const plugin = useActivatedPlugin(pluginID, 'any') const account = useAccount() diff --git a/packages/plugin-infra/src/types.ts b/packages/plugin-infra/src/types.ts index 309b9b3c5af1..9b2209b1bf7d 100644 --- a/packages/plugin-infra/src/types.ts +++ b/packages/plugin-infra/src/types.ts @@ -242,10 +242,8 @@ export namespace Plugin.SNSAdaptor { CompositionDialogEntry?: CompositionDialogEntry /** 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) */ - ToolbarEntry?: ToolbarEntry /** This UI will be rendered as an entry in the wallet status dialog */ - ApplicationEntry?: ApplicationEntry + ApplicationEntries?: ApplicationEntry[] /** This UI will be rendered as sliders on the profile page */ ProfileSliders?: ProfileSlider[] /** This UI will be rendered as tabs on the profile page */ @@ -310,51 +308,15 @@ export namespace Plugin.SNSAdaptor { } // #endregion - // #region Toolbar entry - export interface ToolbarEntry { - image: string - // TODO: remove string - label: I18NStringField | string - /** - * Used to order the toolbars - * - * TODO: can we make them unordered? - */ - priority: number - /** - * This is a React hook. If it returns false, this entry will not be displayed. - */ - useShouldDisplay?(): boolean - /** - * What to do if the entry is clicked. - */ - // TODO: add support for DialogEntry. - // TODO: add support for onClick event. - onClick: 'openCompositionEntry' - } - // #endregion - export interface ApplicationEntry { /** - * The icon image URL - */ - icon: URL - /** - * The name of the application - */ - label: I18NStringField | string - /** - * Also an entrance in a sub-folder + * Render entry component */ - categoryID?: string + RenderEntryComponent: (props: { disabled: boolean }) => JSX.Element /** * Used to order the applications on the board */ - priority: number - /** - * What to do if the application icon is clicked. - */ - onClick(): void + defaultSortingPriority: number } export interface ProfileIdentity { diff --git a/packages/plugin-infra/src/web3/Context.tsx b/packages/plugin-infra/src/web3/Context.tsx index 0e2fb578cee0..be8fd9e12190 100644 --- a/packages/plugin-infra/src/web3/Context.tsx +++ b/packages/plugin-infra/src/web3/Context.tsx @@ -78,7 +78,7 @@ function usePluginsWeb3State() { ) } -export function usePluginIDContext() { +export function useCurrentWeb3NetworkPluginID() { return useContext(PluginIDContext) } @@ -87,7 +87,7 @@ const PluginsWeb3StateContext = createContainer(usePluginsWeb3State) export const usePluginsWeb3StateContext = PluginsWeb3StateContext.useContainer export function usePluginWeb3StateContext(expectedPluginID?: NetworkPluginID) { - const pluginID = usePluginIDContext() + const pluginID = useCurrentWeb3NetworkPluginID() const pluginsWeb3State = usePluginsWeb3StateContext() return pluginsWeb3State[expectedPluginID ?? pluginID] ?? {} } diff --git a/packages/plugin-infra/src/web3/useNetworkDescriptor.ts b/packages/plugin-infra/src/web3/useNetworkDescriptor.ts index 5f906dc28ba2..f7bb10353f38 100644 --- a/packages/plugin-infra/src/web3/useNetworkDescriptor.ts +++ b/packages/plugin-infra/src/web3/useNetworkDescriptor.ts @@ -1,13 +1,13 @@ import type { NetworkPluginID } from '..' import { useNetworkType } from './useNetworkType' -import { usePluginIDContext } from './Context' +import { useCurrentWeb3NetworkPluginID } from './Context' import { getPluginDefine } from '../manager/store' export function useNetworkDescriptor( expectedChainIdOrNetworkTypeOrID?: number | string, expectedPluginID?: NetworkPluginID, ) { - const pluginID = usePluginIDContext() + const pluginID = useCurrentWeb3NetworkPluginID() const pid = expectedPluginID ?? pluginID const networkType = useNetworkType(pid) diff --git a/packages/plugin-infra/src/web3/useNetworkDescriptors.ts b/packages/plugin-infra/src/web3/useNetworkDescriptors.ts index bc344101ae5c..162d5fe303e7 100644 --- a/packages/plugin-infra/src/web3/useNetworkDescriptors.ts +++ b/packages/plugin-infra/src/web3/useNetworkDescriptors.ts @@ -1,7 +1,7 @@ -import { usePluginIDContext } from '.' +import { useCurrentWeb3NetworkPluginID } from '.' import { getPluginDefine } from '..' export function useNetworkDescriptors(expectedPluginID?: string) { - const pluginID = usePluginIDContext() + const pluginID = useCurrentWeb3NetworkPluginID() return getPluginDefine(expectedPluginID ?? pluginID)?.declareWeb3Networks ?? [] } diff --git a/packages/plugin-infra/src/web3/useProviderDescriptor.ts b/packages/plugin-infra/src/web3/useProviderDescriptor.ts index 76f40c997d06..3b48bd3b49d7 100644 --- a/packages/plugin-infra/src/web3/useProviderDescriptor.ts +++ b/packages/plugin-infra/src/web3/useProviderDescriptor.ts @@ -1,10 +1,10 @@ import type { NetworkPluginID } from '..' import { useProviderType } from './useProviderType' -import { usePluginIDContext } from './Context' +import { useCurrentWeb3NetworkPluginID } from './Context' import { getPluginDefine } from '../manager/store' export function useProviderDescriptor(expectedProviderTypeOrID?: string, expectedPluginID?: NetworkPluginID) { - const pluginID = usePluginIDContext() + const pluginID = useCurrentWeb3NetworkPluginID() const providerType = useProviderType(expectedPluginID ?? pluginID) return getPluginDefine(expectedPluginID ?? pluginID)?.declareWeb3Providers?.find((x) => diff --git a/packages/plugin-infra/src/web3/useProviderDescriptors.ts b/packages/plugin-infra/src/web3/useProviderDescriptors.ts index 352b3c3116a0..0db2b0167c14 100644 --- a/packages/plugin-infra/src/web3/useProviderDescriptors.ts +++ b/packages/plugin-infra/src/web3/useProviderDescriptors.ts @@ -1,7 +1,7 @@ -import { usePluginIDContext } from '.' +import { useCurrentWeb3NetworkPluginID } from '.' import { getPluginDefine } from '..' export function useProviderDescriptors(expectedPluginID?: string) { - const pluginID = usePluginIDContext() + const pluginID = useCurrentWeb3NetworkPluginID() return getPluginDefine(expectedPluginID ?? pluginID)?.declareWeb3Providers ?? [] } diff --git a/packages/plugin-infra/src/web3/useWeb3State.ts b/packages/plugin-infra/src/web3/useWeb3State.ts index 07689afb6548..381cb694a293 100644 --- a/packages/plugin-infra/src/web3/useWeb3State.ts +++ b/packages/plugin-infra/src/web3/useWeb3State.ts @@ -1,8 +1,8 @@ -import { usePluginIDContext } from './Context' +import { useCurrentWeb3NetworkPluginID } from './Context' import { useActivatedPluginWeb3State } from '../hooks/useActivatedPluginWeb3State' import type { NetworkPluginID } from '..' export function useWeb3State(expectedPluginID?: NetworkPluginID) { - const pluginID = usePluginIDContext() + const pluginID = useCurrentWeb3NetworkPluginID() return useActivatedPluginWeb3State(expectedPluginID ?? pluginID) ?? {} } diff --git a/packages/plugin-infra/src/web3/useWeb3UI.ts b/packages/plugin-infra/src/web3/useWeb3UI.ts index c30e3eb98baa..4a23eb31c66d 100644 --- a/packages/plugin-infra/src/web3/useWeb3UI.ts +++ b/packages/plugin-infra/src/web3/useWeb3UI.ts @@ -1,8 +1,8 @@ -import { usePluginIDContext } from './Context' +import { useCurrentWeb3NetworkPluginID } from './Context' import { useActivatedPluginWeb3UI } from '../hooks/useActivatedPluginWeb3UI' import type { NetworkPluginID } from '..' export function useWeb3UI(expectedPluginID?: NetworkPluginID) { - const pluginID = usePluginIDContext() + const pluginID = useCurrentWeb3NetworkPluginID() return useActivatedPluginWeb3UI(expectedPluginID ?? pluginID) ?? {} } diff --git a/packages/plugins/CyberConnect/src/SNSAdaptor/ConnectButton.tsx b/packages/plugins/CyberConnect/src/SNSAdaptor/ConnectButton.tsx index da4bdf16d6d2..531f6b007dad 100644 --- a/packages/plugins/CyberConnect/src/SNSAdaptor/ConnectButton.tsx +++ b/packages/plugins/CyberConnect/src/SNSAdaptor/ConnectButton.tsx @@ -1,7 +1,7 @@ import { useEffect, useState, useCallback } from 'react' import { makeStyles, MaskColorVar } from '@masknet/theme' import { useWeb3, isSameAddress } from '@masknet/web3-shared-evm' -import { useAccount, usePluginIDContext, NetworkPluginID } from '@masknet/plugin-infra' +import { useAccount, useCurrentWeb3NetworkPluginID, NetworkPluginID } from '@masknet/plugin-infra' import CyberConnect, { Env } from '@cyberlab/cyberconnect' import { PluginCyberConnectRPC } from '../messages' import { CircularProgress, useTheme, Typography } from '@mui/material' @@ -96,7 +96,7 @@ export default function ConnectButton({ const [cc, setCc] = useState(null) const [isFollowing, setIsFollowing] = useState(false) const [isLoading, setIsLoading] = useState(false) - const blockChainNetwork = usePluginIDContext() + const blockChainNetwork = useCurrentWeb3NetworkPluginID() useAsync(async () => { if (isSameAddress(myAddress, address)) return const res = await PluginCyberConnectRPC.fetchFollowStatus(myAddress, address) diff --git a/packages/plugins/FileService/src/SNSAdaptor/index.tsx b/packages/plugins/FileService/src/SNSAdaptor/index.tsx index 279620daec0a..b38c6466452a 100644 --- a/packages/plugins/FileService/src/SNSAdaptor/index.tsx +++ b/packages/plugins/FileService/src/SNSAdaptor/index.tsx @@ -8,6 +8,8 @@ import type { FileInfo } from '../types' import FileServiceDialog from './MainDialog' import { Preview } from './Preview' import { FileServiceIcon } from '@masknet/icons' +import { CrossIsolationMessages } from '@masknet/shared-base' +import { ApplicationEntry } from '@masknet/shared' const definition: Plugin.SNSAdaptor.Definition = { ...base, @@ -32,6 +34,29 @@ const definition: Plugin.SNSAdaptor.Definition = { }, dialog: FileServiceDialog, }, + ApplicationEntries: [ + { + RenderEntryComponent({ disabled }) { + return ( + + CrossIsolationMessages.events.requestComposition.sendToLocal({ + reason: 'timeline', + open: true, + options: { + startupPlugin: base.ID, + }, + }) + } + /> + ) + }, + defaultSortingPriority: 2, + }, + ], } export default definition diff --git a/packages/shared/src/UI/components/ApplicationEntry/index.tsx b/packages/shared/src/UI/components/ApplicationEntry/index.tsx new file mode 100644 index 000000000000..206536e6966f --- /dev/null +++ b/packages/shared/src/UI/components/ApplicationEntry/index.tsx @@ -0,0 +1,58 @@ +import classNames from 'classnames' +import { makeStyles } from '@masknet/theme' +import { Typography } from '@mui/material' + +const useStyles = makeStyles()((theme) => ({ + applicationBox: { + display: 'flex', + flexDirection: 'column', + justifyContent: 'center', + alignItems: 'center', + backgroundColor: theme.palette.background.default, + borderRadius: '8px', + + height: 100, + }, + applicationBoxHover: { + cursor: 'pointer', + '&:hover': { + transform: 'scale(1.05) translateY(-4px)', + boxShadow: theme.palette.mode === 'light' ? '0px 10px 16px rgba(0, 0, 0, 0.1)' : 'none', + }, + }, + applicationImg: { + width: 36, + height: 36, + marginBottom: 10, + }, + title: { + fontSize: 15, + }, + disabled: { + opacity: 0.4, + cursor: 'default', + pointerEvent: 'none', + }, +})) + +interface Props { + icon: string + title: string + disabled?: boolean + onClick: () => void +} + +export function ApplicationEntry(props: Props) { + const { icon, title, onClick, disabled = false } = props + const { classes } = useStyles() + return ( +
{} : onClick}> + + + {title} + +
+ ) +} diff --git a/packages/shared/src/UI/components/index.ts b/packages/shared/src/UI/components/index.ts index b4d86259c80c..b32738abcf4a 100644 --- a/packages/shared/src/UI/components/index.ts +++ b/packages/shared/src/UI/components/index.ts @@ -13,3 +13,4 @@ export * from './I18NextProviderHMR' export * from './AssetPlayer' export * from './NFTCardStyledAssetPlayer' export * from './ReversedAddress' +export * from './ApplicationEntry' diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e7dfa2ba128d..562f36236d13 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -23427,7 +23427,7 @@ packages: safe-buffer: 5.2.1 tough-cookie: 2.5.0 tunnel-agent: 0.6.0 - uuid: 3.3.2 + uuid: 3.4.0 dev: false /require-directory/2.1.1: From 15ab3d9e94b0574d1c8d2573fd14715b22714f8d Mon Sep 17 00:00:00 2001 From: Hancheng Zhou Date: Thu, 31 Mar 2022 16:49:18 +0800 Subject: [PATCH 14/42] fix: app board wallet disconnected display (#6007) * fix: app board disconnected * chore: add empty conflux constants --- docs/evm-integration.md | 4 ++++ .../mask/src/components/shared/ApplicationBoard.tsx | 8 ++++---- packages/web3-constants/compile-constants.ts | 1 + packages/web3-constants/evm/airdrop.json | 3 ++- packages/web3-constants/evm/artblocks.json | 3 ++- packages/web3-constants/evm/cryptoartai.json | 9 ++++++--- packages/web3-constants/evm/dhedge.json | 6 ++++-- packages/web3-constants/evm/ethereum.json | 6 ++++-- packages/web3-constants/evm/explorer.json | 6 ++++-- packages/web3-constants/evm/gitcoin.json | 12 ++++++++---- packages/web3-constants/evm/good-ghosting.json | 6 ++++-- packages/web3-constants/evm/ito.json | 12 ++++++++---- packages/web3-constants/evm/lbp.json | 3 ++- packages/web3-constants/evm/mask-box.json | 6 ++++-- packages/web3-constants/evm/openocean.json | 3 ++- packages/web3-constants/evm/opensea-api.json | 9 ++++++--- packages/web3-constants/evm/pooltogether.json | 6 ++++-- packages/web3-constants/evm/red-packet.json | 12 ++++++++---- packages/web3-constants/evm/savings.json | 9 ++++++--- .../web3-constants/evm/space-station-galaxy.json | 6 ++++-- packages/web3-constants/evm/trending.json | 9 ++++++--- 21 files changed, 93 insertions(+), 46 deletions(-) diff --git a/docs/evm-integration.md b/docs/evm-integration.md index 7cfddfc9ecf8..489dc889bd55 100644 --- a/docs/evm-integration.md +++ b/docs/evm-integration.md @@ -30,6 +30,10 @@ Mask Network fetches on-chain data from various data sources. Therefore, you can - +### Web3 Constants Compile Config + +Add the chain name to `compileConstants()` in `packages/web3-constants/compile-constants.ts`. + ### Token List The team maintains a token list . So free feel to create one for the chain. And add the token list link to `packages/web3-constants/evm/token-list.json`. diff --git a/packages/mask/src/components/shared/ApplicationBoard.tsx b/packages/mask/src/components/shared/ApplicationBoard.tsx index 1085906290d5..3762504887d9 100644 --- a/packages/mask/src/components/shared/ApplicationBoard.tsx +++ b/packages/mask/src/components/shared/ApplicationBoard.tsx @@ -1,8 +1,7 @@ import { Fragment } from 'react' import { makeStyles } from '@masknet/theme' import { useChainId } from '@masknet/web3-shared-evm' -import { useActivatedPluginsSNSAdaptor, useCurrentWeb3NetworkPluginID } from '@masknet/plugin-infra' -import type { Plugin } from '@masknet/plugin-infra' +import { useActivatedPluginsSNSAdaptor, useCurrentWeb3NetworkPluginID, Plugin, useAccount } from '@masknet/plugin-infra' import { getCurrentSNSNetwork } from '../../social-network-adaptor/utils' import { activatedSocialNetworkUI } from '../../social-network' @@ -32,6 +31,7 @@ export function ApplicationBoard() { const snsAdaptorPlugins = useActivatedPluginsSNSAdaptor('any') const currentWeb3Network = useCurrentWeb3NetworkPluginID() const chainId = useChainId() + const account = useAccount() const currentSNSNetwork = getCurrentSNSNetwork(activatedSocialNetworkUI.networkIdentifier) return ( @@ -46,7 +46,7 @@ export function ApplicationBoard() { currentWeb3NetworkSupportedChainIds === undefined || currentWeb3NetworkSupportedChainIds.supportedChainIds?.includes(chainId), ) - + const isWalletConnectedRequired = currentWeb3NetworkSupportedChainIds !== undefined const currentSNSIsSupportedNetwork = cur.enableRequirement.networks.networks[currentSNSNetwork] const isSNSEnabled = @@ -56,7 +56,7 @@ export function ApplicationBoard() { cur.ApplicationEntries.map((x) => { return { entry: x, - enabled: isWeb3Enabled && isSNSEnabled, + enabled: isSNSEnabled && (account ? isWeb3Enabled : !isWalletConnectedRequired), pluginId: cur.ID, } }) ?? [], diff --git a/packages/web3-constants/compile-constants.ts b/packages/web3-constants/compile-constants.ts index cafdb8aa29af..e9462b36f726 100644 --- a/packages/web3-constants/compile-constants.ts +++ b/packages/web3-constants/compile-constants.ts @@ -59,6 +59,7 @@ compileConstants(path.join(__dirname, 'evm'), [ 'Fantom', 'Aurora', 'Aurora_Testnet', + 'Conflux', ]) compileConstants(path.join(__dirname, 'solana'), ['Mainnet', 'Testnet', 'Devnet']) diff --git a/packages/web3-constants/evm/airdrop.json b/packages/web3-constants/evm/airdrop.json index ab949267d4f5..28ca1f00abf1 100644 --- a/packages/web3-constants/evm/airdrop.json +++ b/packages/web3-constants/evm/airdrop.json @@ -17,6 +17,7 @@ "Celo": "", "Fantom": "", "Aurora": "", - "Aurora_Testnet": "" + "Aurora_Testnet": "", + "Conflux": "" } } diff --git a/packages/web3-constants/evm/artblocks.json b/packages/web3-constants/evm/artblocks.json index b626e1dae9f6..0ac17edfdcae 100644 --- a/packages/web3-constants/evm/artblocks.json +++ b/packages/web3-constants/evm/artblocks.json @@ -17,6 +17,7 @@ "Celo": "", "Fantom": "", "Aurora": "", - "Aurora_Testnet": "" + "Aurora_Testnet": "", + "Conflux": "" } } diff --git a/packages/web3-constants/evm/cryptoartai.json b/packages/web3-constants/evm/cryptoartai.json index edde7f04abdc..8819260601ef 100644 --- a/packages/web3-constants/evm/cryptoartai.json +++ b/packages/web3-constants/evm/cryptoartai.json @@ -17,7 +17,8 @@ "Celo": "", "Fantom": "", "Aurora": "", - "Aurora_Testnet": "" + "Aurora_Testnet": "", + "Conflux": "" }, "ARTIST_ACCEPTING_BIDS_V2": { "Mainnet": "0x78C889749f29D2965a76Ede3BBb232A9729Ccf0b", @@ -37,7 +38,8 @@ "Celo": "", "Fantom": "", "Aurora": "", - "Aurora_Testnet": "" + "Aurora_Testnet": "", + "Conflux": "" }, "CANFT_MARKET": { "Mainnet": "0x72d081953957723e540780a0C6bA31725469238E", @@ -57,6 +59,7 @@ "Celo": "", "Fantom": "", "Aurora": "", - "Aurora_Testnet": "" + "Aurora_Testnet": "", + "Conflux": "" } } diff --git a/packages/web3-constants/evm/dhedge.json b/packages/web3-constants/evm/dhedge.json index 870f99083e7f..9aa7b2dbd671 100644 --- a/packages/web3-constants/evm/dhedge.json +++ b/packages/web3-constants/evm/dhedge.json @@ -17,7 +17,8 @@ "Celo": "", "Fantom": "", "Aurora": "", - "Aurora_Testnet": "" + "Aurora_Testnet": "", + "Conflux": "" }, "API_URL": { "Mainnet": "https://api-v2.dhedge.org/graphql", @@ -37,6 +38,7 @@ "Celo": "", "Fantom": "", "Aurora": "", - "Aurora_Testnet": "" + "Aurora_Testnet": "", + "Conflux": "" } } diff --git a/packages/web3-constants/evm/ethereum.json b/packages/web3-constants/evm/ethereum.json index 4e4fefb89d3b..9915418599d4 100644 --- a/packages/web3-constants/evm/ethereum.json +++ b/packages/web3-constants/evm/ethereum.json @@ -59,7 +59,8 @@ "Celo": "", "Fantom": "", "Aurora": "", - "Aurora_Testnet": "" + "Aurora_Testnet": "", + "Conflux": "" }, "ENS_REVERSE_RECORDS_ADDRESS": { "Mainnet": "0x3671aE578E63FdF66ad4F3E12CC0c0d71Ac7510C", @@ -79,6 +80,7 @@ "Celo": "", "Fantom": "", "Aurora": "", - "Aurora_Testnet": "" + "Aurora_Testnet": "", + "Conflux": "" } } diff --git a/packages/web3-constants/evm/explorer.json b/packages/web3-constants/evm/explorer.json index a3c5bf0d117e..55f6e2a86fc2 100644 --- a/packages/web3-constants/evm/explorer.json +++ b/packages/web3-constants/evm/explorer.json @@ -17,7 +17,8 @@ "Celo": [], "Fantom": ["AST4WWPNEYDURUXG2GH32JZMYWEFDP999S"], "Aurora": [], - "Aurora_Testnet": [] + "Aurora_Testnet": [], + "Conflux": [] }, "EXPLORER_API": { "Mainnet": "https://api.etherscan.io/api", @@ -37,6 +38,7 @@ "Celo": "https://explorer.celo.org/api", "Fantom": "https://api.ftmscan.com/api", "Aurora": "https://explorer.mainnet.aurora.dev/api", - "Aurora_Testnet": "https://explorer.testnet.aurora.dev/api" + "Aurora_Testnet": "https://explorer.testnet.aurora.dev/api", + "Conflux": "" } } diff --git a/packages/web3-constants/evm/gitcoin.json b/packages/web3-constants/evm/gitcoin.json index 708e296ea6de..c26772f90dd9 100644 --- a/packages/web3-constants/evm/gitcoin.json +++ b/packages/web3-constants/evm/gitcoin.json @@ -17,7 +17,8 @@ "Celo": "", "Fantom": "", "Aurora": "", - "Aurora_Testnet": "" + "Aurora_Testnet": "", + "Conflux": "" }, "BULK_CHECKOUT_ADDRESS": { "Mainnet": "0x7d655c57f71464B6f83811C55D84009Cd9f5221C", @@ -37,7 +38,8 @@ "Celo": "", "Fantom": "", "Aurora": "", - "Aurora_Testnet": "" + "Aurora_Testnet": "", + "Conflux": "" }, "GITCOIN_ETH_ADDRESS": { "Mainnet": "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE", @@ -57,7 +59,8 @@ "Celo": "", "Fantom": "", "Aurora": "", - "Aurora_Testnet": "" + "Aurora_Testnet": "", + "Conflux": "" }, "GITCOIN_TIP_PERCENTAGE": { "Mainnet": 5, @@ -77,6 +80,7 @@ "Celo": 0, "Fantom": 0, "Aurora": 0, - "Aurora_Testnet": 0 + "Aurora_Testnet": 0, + "Conflux": 0 } } diff --git a/packages/web3-constants/evm/good-ghosting.json b/packages/web3-constants/evm/good-ghosting.json index e54f1e6ba1bf..9ab7b3a1ba84 100644 --- a/packages/web3-constants/evm/good-ghosting.json +++ b/packages/web3-constants/evm/good-ghosting.json @@ -17,7 +17,8 @@ "Celo": "", "Fantom": "", "Aurora": "", - "Aurora_Testnet": "" + "Aurora_Testnet": "", + "Conflux": "" }, "GOOD_GHOSTING_INCENTIVES_CONTRACT_ADDRESS": { "Mainnet": "", @@ -37,6 +38,7 @@ "Celo": "", "Fantom": "", "Aurora": "", - "Aurora_Testnet": "" + "Aurora_Testnet": "", + "Conflux": "" } } diff --git a/packages/web3-constants/evm/ito.json b/packages/web3-constants/evm/ito.json index f15c7c3a47e6..7a56f24e5d98 100644 --- a/packages/web3-constants/evm/ito.json +++ b/packages/web3-constants/evm/ito.json @@ -17,7 +17,8 @@ "Celo": "", "Fantom": "", "Aurora": "", - "Aurora_Testnet": "" + "Aurora_Testnet": "", + "Conflux": "" }, "MASK_ITO_CONTRACT_ADDRESS": { "Mainnet": "0x86812da3A623ab9606976078588b80C315E55FA3", @@ -37,7 +38,8 @@ "Celo": "", "Fantom": "", "Aurora": "", - "Aurora_Testnet": "" + "Aurora_Testnet": "", + "Conflux": "" }, "ITO2_CONTRACT_ADDRESS": { "Mainnet": "0xc2CFbF22d6Dc87D0eE18d38d73733524c109Ff46", @@ -99,7 +101,8 @@ "Celo": "", "Fantom": "", "Aurora": "", - "Aurora_Testnet": "" + "Aurora_Testnet": "", + "Conflux": "" }, "DEFAULT_QUALIFICATION2_ADDRESS": { "Mainnet": "0x4dC5f343Fe57E4fbDA1B454d125D396A3181272c", @@ -140,6 +143,7 @@ "Celo": "https://api.thegraph.com/subgraphs/name/dimensiondev/mask-ito-celo", "Fantom": "https://api.thegraph.com/subgraphs/name/dimensiondev/mask-ito-fantom", "Aurora": "https://api.thegraph.com/subgraphs/name/dimensiondev/mask-ito-aurora", - "Aurora_Testnet": "" + "Aurora_Testnet": "", + "Conflux": "" } } diff --git a/packages/web3-constants/evm/lbp.json b/packages/web3-constants/evm/lbp.json index 051943e8a62d..4e867a9c5741 100644 --- a/packages/web3-constants/evm/lbp.json +++ b/packages/web3-constants/evm/lbp.json @@ -17,6 +17,7 @@ "Celo": "", "Fantom": "", "Aurora": "", - "Aurora_Testnet": "" + "Aurora_Testnet": "", + "Conflux": "" } } diff --git a/packages/web3-constants/evm/mask-box.json b/packages/web3-constants/evm/mask-box.json index a391a2ea2256..d1bc8e10c0f8 100644 --- a/packages/web3-constants/evm/mask-box.json +++ b/packages/web3-constants/evm/mask-box.json @@ -17,7 +17,8 @@ "Celo": "", "Fantom": "", "Aurora": "0xf5056B96ab242C566002852d0b98ce0BcDf1af51", - "Aurora_Testnet": "0xB4D669bc117735FdA44e90e52795132187705B21" + "Aurora_Testnet": "0xB4D669bc117735FdA44e90e52795132187705B21", + "Conflux": "" }, "MASK_BOX_CONTRACT_FROM_BLOCK": { "Mainnet": 13687866, @@ -37,6 +38,7 @@ "Celo": 0, "Fantom": 0, "Aurora": 57259004, - "Aurora_Testnet": 77919118 + "Aurora_Testnet": 77919118, + "Conflux": 0 } } diff --git a/packages/web3-constants/evm/openocean.json b/packages/web3-constants/evm/openocean.json index 50fb7755a589..a0004c674b66 100644 --- a/packages/web3-constants/evm/openocean.json +++ b/packages/web3-constants/evm/openocean.json @@ -17,6 +17,7 @@ "Celo": "0x934B510D4C9103E6a87AEf13b816fb080286D649", "Fantom": "0x934B510D4C9103E6a87AEf13b816fb080286D649", "Aurora": "", - "Aurora_Testnet": "" + "Aurora_Testnet": "", + "Conflux": "" } } diff --git a/packages/web3-constants/evm/opensea-api.json b/packages/web3-constants/evm/opensea-api.json index 8032d46e99ce..eec5cbdb1162 100644 --- a/packages/web3-constants/evm/opensea-api.json +++ b/packages/web3-constants/evm/opensea-api.json @@ -17,7 +17,8 @@ "Celo": "", "Fantom": "", "Aurora": "", - "Aurora_Testnet": "" + "Aurora_Testnet": "", + "Conflux": "" }, "GET_SINGLE_ASSET_URL": { "Mainnet": "https://api.opensea.io/api/v1/asset", @@ -37,7 +38,8 @@ "Celo": "", "Fantom": "", "Aurora": "", - "Aurora_Testnet": "" + "Aurora_Testnet": "", + "Conflux": "" }, "GET_ASSETS_URL": { "Mainnet": "https://api.opensea.io/api/v1/assets", @@ -57,6 +59,7 @@ "Celo": "", "Fantom": "", "Aurora": "", - "Aurora_Testnet": "" + "Aurora_Testnet": "", + "Conflux": "" } } diff --git a/packages/web3-constants/evm/pooltogether.json b/packages/web3-constants/evm/pooltogether.json index 529a2e16bb28..ea3096e69ea4 100644 --- a/packages/web3-constants/evm/pooltogether.json +++ b/packages/web3-constants/evm/pooltogether.json @@ -17,7 +17,8 @@ "Celo": "", "Fantom": "", "Aurora": "", - "Aurora_Testnet": "" + "Aurora_Testnet": "", + "Conflux": "" }, "MASK_POOL_ADDRESS": { "Mainnet": "", @@ -37,6 +38,7 @@ "Celo": "", "Fantom": "", "Aurora": "", - "Aurora_Testnet": "" + "Aurora_Testnet": "", + "Conflux": "" } } diff --git a/packages/web3-constants/evm/red-packet.json b/packages/web3-constants/evm/red-packet.json index f88e4a77a16d..3fc873e50bb9 100644 --- a/packages/web3-constants/evm/red-packet.json +++ b/packages/web3-constants/evm/red-packet.json @@ -17,7 +17,8 @@ "Celo": "", "Fantom": "", "Aurora": "", - "Aurora_Testnet": "" + "Aurora_Testnet": "", + "Conflux": "" }, "HAPPY_RED_PACKET_ADDRESS_V2": { "Mainnet": "0x8D8912E1237F9FF3EF661F32743CFB276E052F98", @@ -37,7 +38,8 @@ "Celo": "", "Fantom": "", "Aurora": "", - "Aurora_Testnet": "" + "Aurora_Testnet": "", + "Conflux": "" }, "HAPPY_RED_PACKET_ADDRESS_V3": { "Mainnet": "", @@ -57,7 +59,8 @@ "Celo": "", "Fantom": "", "Aurora": "", - "Aurora_Testnet": "" + "Aurora_Testnet": "", + "Conflux": "" }, "HAPPY_RED_PACKET_ADDRESS_V4": { "Mainnet": "0xaBBe1101FD8fa5847c452A6D70C8655532B03C33", @@ -119,6 +122,7 @@ "Celo": "https://api.thegraph.com/subgraphs/name/dimensiondev/mask-red-packet-celo", "Fantom": "https://api.thegraph.com/subgraphs/name/dimensiondev/mask-red-packet-fantom", "Aurora": "https://api.thegraph.com/subgraphs/name/dimensiondev/mask-red-packet-aurora", - "Aurora_Testnet": "" + "Aurora_Testnet": "", + "Conflux": "" } } diff --git a/packages/web3-constants/evm/savings.json b/packages/web3-constants/evm/savings.json index 0f58f923eb48..3372aaf2c0d1 100644 --- a/packages/web3-constants/evm/savings.json +++ b/packages/web3-constants/evm/savings.json @@ -17,7 +17,8 @@ "Celo": "", "Fantom": "", "Aurora": "", - "Aurora_Testnet": "" + "Aurora_Testnet": "", + "Conflux": "" }, "LIDO_STETH": { "Mainnet": "0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84", @@ -37,7 +38,8 @@ "Celo": "", "Fantom": "", "Aurora": "", - "Aurora_Testnet": "" + "Aurora_Testnet": "", + "Conflux": "" }, "LIDO_REFERRAL_ADDRESS": { "Mainnet": "0x278D7e418a28ff763eEeDf29238CD6dfcade3A3a", @@ -57,6 +59,7 @@ "Celo": "", "Fantom": "", "Aurora": "", - "Aurora_Testnet": "" + "Aurora_Testnet": "", + "Conflux": "" } } diff --git a/packages/web3-constants/evm/space-station-galaxy.json b/packages/web3-constants/evm/space-station-galaxy.json index 86b85572cdcd..28bd2f7c41ed 100644 --- a/packages/web3-constants/evm/space-station-galaxy.json +++ b/packages/web3-constants/evm/space-station-galaxy.json @@ -17,7 +17,8 @@ "Celo": "", "Fantom": "", "Aurora": "", - "Aurora_Testnet": "" + "Aurora_Testnet": "", + "Conflux": "" }, "SUBGRAPH_URL": { "Mainnet": "", @@ -37,6 +38,7 @@ "Celo": "", "Fantom": "", "Aurora": "", - "Aurora_Testnet": "" + "Aurora_Testnet": "", + "Conflux": "" } } diff --git a/packages/web3-constants/evm/trending.json b/packages/web3-constants/evm/trending.json index a115fe46afe5..4848e30aa5d4 100644 --- a/packages/web3-constants/evm/trending.json +++ b/packages/web3-constants/evm/trending.json @@ -17,7 +17,8 @@ "Celo": "", "Fantom": "", "Aurora": "", - "Aurora_Testnet": "" + "Aurora_Testnet": "", + "Conflux": "" }, "UNISWAP_V2_HEALTH_URL": { "Mainnet": "https://api.thegraph.com/index-node/graphql", @@ -37,7 +38,8 @@ "Celo": "", "Fantom": "", "Aurora": "", - "Aurora_Testnet": "" + "Aurora_Testnet": "", + "Conflux": "" }, "ETHEREUM_BLOCKS_SUBGRAPH_URL": { "Mainnet": "https://api.thegraph.com/subgraphs/name/blocklytics/ethereum-blocks", @@ -57,6 +59,7 @@ "Celo": "", "Fantom": "", "Aurora": "", - "Aurora_Testnet": "" + "Aurora_Testnet": "", + "Conflux": "" } } From a5c7770950b39c9eb460bbaa0c08961c49401fe9 Mon Sep 17 00:00:00 2001 From: zhouhanseng Date: Thu, 31 Mar 2022 18:52:00 +0800 Subject: [PATCH 15/42] fix: typo --- packages/mask/shared-ui/locales/ja-JP.json | 2 +- packages/mask/shared-ui/locales/ko-KR.json | 2 +- packages/mask/shared-ui/locales/zh-CN.json | 2 +- packages/mask/shared-ui/locales/zh-TW.json | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/mask/shared-ui/locales/ja-JP.json b/packages/mask/shared-ui/locales/ja-JP.json index ddbe55582ad1..516839e6c041 100644 --- a/packages/mask/shared-ui/locales/ja-JP.json +++ b/packages/mask/shared-ui/locales/ja-JP.json @@ -239,7 +239,7 @@ "plugin_ito_qualification_start_time": "参加資格開始時間:", "plugin_ito_error_qualification_start_time": "無効:資格開始時間は ITO の終了時間よりも前でなくてはいけません", "plugin_ito_error_invalid_qualification": "無効な資格アドレス", - "plugin_ito_unlock_time": "ロック解除時間 {{zone}}", + "plugin_ito_unlock_time": "ロック解除時間", "plugin_ito_qualification_label": "プラグインのコントラクト", "plugin_ito_message_label": "タイトル", "plugin_ito_region_label": "IP リージョンの選択", diff --git a/packages/mask/shared-ui/locales/ko-KR.json b/packages/mask/shared-ui/locales/ko-KR.json index 7f6d0b03a5c8..f95356fe192c 100644 --- a/packages/mask/shared-ui/locales/ko-KR.json +++ b/packages/mask/shared-ui/locales/ko-KR.json @@ -432,7 +432,7 @@ "plugin_ito_error_qualification_start_time": "주의: 자격 인정 시작 시간이 ITO 종료 시간보다 빨아야 합니다.", "plugin_ito_error_invalid_qualification": "무효한 인증 주소입니다.", "plugin_ito_unlock_time_cert": "ITO Mask 언락 시간은 {{date}}.", - "plugin_ito_unlock_time": "언락 시간 {{zone}}", + "plugin_ito_unlock_time": "언락 시간", "plugin_ito_launch_campaign": "SocialFi Launch Campaign", "plugin_ito_total_claimable_count": "전체: ", "plugin_ito_qualification_label": "플러그인 컨트랙트", diff --git a/packages/mask/shared-ui/locales/zh-CN.json b/packages/mask/shared-ui/locales/zh-CN.json index 632e58ff618c..233212b2f97d 100644 --- a/packages/mask/shared-ui/locales/zh-CN.json +++ b/packages/mask/shared-ui/locales/zh-CN.json @@ -532,7 +532,7 @@ "plugin_ito_error_qualification_start_time": "无效:资格认证开始时间应该早于ITO结束时间", "plugin_ito_error_invalid_qualification": "无效的资格认证地址", "plugin_ito_unlock_time_cert": "ITO Mask 解锁时间为 {{date}}。", - "plugin_ito_unlock_time": "解锁时间 {{zone}}", + "plugin_ito_unlock_time": "解锁时间", "plugin_ito_total_claimable_count": "总计: ", "plugin_ito_qualification_label": "插件合约", "plugin_ito_message_label": "标题", diff --git a/packages/mask/shared-ui/locales/zh-TW.json b/packages/mask/shared-ui/locales/zh-TW.json index 0d750aed3bd7..3b743e3e12b6 100644 --- a/packages/mask/shared-ui/locales/zh-TW.json +++ b/packages/mask/shared-ui/locales/zh-TW.json @@ -376,7 +376,7 @@ "plugin_ito_qualification_start_time": "資格開始時間:", "plugin_ito_error_qualification_start_time": "錯誤:資格開始時間應早於 ITO 結束時間", "plugin_ito_error_invalid_qualification": "錯誤的資格地址", - "plugin_ito_unlock_time": "解鎖時間 {{zone}}", + "plugin_ito_unlock_time": "解鎖時間", "plugin_ito_total_claimable_count": "總計: ", "plugin_ito_qualification_label": "插件合約", "plugin_ito_message_label": "標題", From c9f9bae8ea83015d9c316c053c01936a62ff56ab Mon Sep 17 00:00:00 2001 From: Hancheng Zhou Date: Thu, 31 Mar 2022 18:54:14 +0800 Subject: [PATCH 16/42] refactor: ito card footer button (#5985) * refactor: ito card footer button * chore: rename component --- .../mask/src/plugins/ITO/SNSAdaptor/ITO.tsx | 361 ++++++++++-------- 1 file changed, 207 insertions(+), 154 deletions(-) diff --git a/packages/mask/src/plugins/ITO/SNSAdaptor/ITO.tsx b/packages/mask/src/plugins/ITO/SNSAdaptor/ITO.tsx index d35d84c6d41a..2e910ff9d7fb 100644 --- a/packages/mask/src/plugins/ITO/SNSAdaptor/ITO.tsx +++ b/packages/mask/src/plugins/ITO/SNSAdaptor/ITO.tsx @@ -493,7 +493,7 @@ export function ITO(props: ITO_Props) { tradeInfo?.buyInfo?.token.symbol, ]) - const footerStartTime = useMemo(() => { + const FooterStartTime = useMemo(() => { return ( {t('plugin_ito_list_start_date', { date: formatDateTime(startTime, 'yyyy-MM-dd HH:mm') })} @@ -501,7 +501,7 @@ export function ITO(props: ITO_Props) { ) }, [startTime]) - const footerEndTime = useMemo( + const FooterEndTime = useMemo( () => ( {t('plugin_ito_swap_end_date', { date: formatDateTime(endTime, 'yyyy-MM-dd HH:mm') })} @@ -510,13 +510,13 @@ export function ITO(props: ITO_Props) { [endTime, t], ) - const footerSwapInfo = useMemo( + const FooterSwapInfo = useMemo( () => ( <> {swapResultText} - {footerEndTime} + {FooterEndTime} {hasLockTime && !isUnlocked && unlockTime > Date.now() && @@ -529,10 +529,10 @@ export function ITO(props: ITO_Props) { ) : null} ), - [footerEndTime, swapResultText], + [FooterEndTime, swapResultText], ) - const footerNormal = useMemo( + const FooterNormal = useMemo( () => ( <> @@ -543,13 +543,82 @@ export function ITO(props: ITO_Props) { {listOfStatus.includes(ITO_Status.waited) - ? footerStartTime + ? FooterStartTime : listOfStatus.includes(ITO_Status.started) - ? footerEndTime + ? FooterEndTime : null} ), - [footerEndTime, footerStartTime, limit, listOfStatus, token.decimals, token.symbol], + [FooterEndTime, FooterStartTime, limit, listOfStatus, token.decimals, token.symbol], + ) + + const FooterBuyerLockedButton = useMemo(() => { + if (!availability?.claimed) { + return ( + + {claimState.type === TransactionStateType.HASH ? t('plugin_ito_claiming') : t('plugin_ito_claim')} + + ) + } + + if (canWithdraw) { + return ( + + {t('plugin_ito_withdraw')} + + ) + } + return null + }, [availability?.claimed, canWithdraw, claimState]) + + const FooterBuyerWithLockTimeButton = useMemo( + () => ( + + {(() => { + if (isUnlocked) return FooterBuyerLockedButton + + return ( + undefined} + variant="contained" + disabled + size="large" + className={classNames(classes.actionButton, classes.textInOneLine)}> + {t('plugin_ito_claim')} + + ) + })()} + + ), + [noRemain, listOfStatus, isUnlocked], + ) + + const FooterBuyerButton = useMemo( + () => ( + + {(() => { + if (hasLockTime) return FooterBuyerWithLockTimeButton + if (canWithdraw) { + return ( + + {t('plugin_ito_withdraw')} + + ) + } + return null + })()} + + ), + [hasLockTime, canWithdraw], ) return ( @@ -611,10 +680,10 @@ export function ITO(props: ITO_Props) {
{isBuyer - ? footerSwapInfo + ? FooterSwapInfo : listOfStatus.includes(ITO_Status.expired) - ? footerEndTime - : footerNormal} + ? FooterEndTime + : FooterNormal}
From: @{sellerName} @@ -623,163 +692,147 @@ export function ITO(props: ITO_Props) { - {loadingRegion && isRegionRestrict ? null : !isRegionAllow ? ( - undefined} - variant="contained" - size="large" - className={classes.actionButton}> - {t('plugin_ito_region_ban')} - - ) : (noRemain || listOfStatus.includes(ITO_Status.expired)) && - !canWithdraw && - ((availability?.claimed && hasLockTime) || !hasLockTime) ? null : loadingTradeInfo || - loadingAvailability ? ( - undefined} - variant="contained" - size="large" - className={classes.actionButton}> - {t('plugin_ito_loading')} - - ) : !account || !chainIdValid ? ( - - {t('plugin_wallet_connect_a_wallet')} - - ) : isBuyer ? ( - - {hasLockTime ? ( - - {isUnlocked ? ( - !availability?.claimed ? ( - - {claimState.type === TransactionStateType.HASH - ? t('plugin_ito_claiming') - : t('plugin_ito_claim')} - - ) : canWithdraw ? ( - - {t('plugin_ito_withdraw')} - - ) : null - ) : ( - undefined} - variant="contained" - disabled - size="large" - className={classNames(classes.actionButton, classes.textInOneLine)}> - {t('plugin_ito_claim')} - - )} - - ) : canWithdraw ? ( - - - {t('plugin_ito_withdraw')} - - - ) : null} - {noRemain || listOfStatus.includes(ITO_Status.expired) ? null : ( - - - {t('plugin_ito_share')} - - - )} - - ) : canWithdraw ? ( - - {t('plugin_ito_withdraw')} - - ) : (!ifQualified || !(ifQualified as Qual_V2).qualified) && - !isNativeTokenAddress(qualificationAddress) ? ( - - {loadingIfQualified - ? t('plugin_ito_qualification_loading') - : !ifQualified - ? t('plugin_ito_qualification_failed') - : !(ifQualified as Qual_V2).qualified - ? startCase((ifQualified as Qual_V2).errorMsg) - : null} - - ) : listOfStatus.includes(ITO_Status.expired) ? null : listOfStatus.includes(ITO_Status.waited) ? ( - - + {(() => { + if (loadingRegion && isRegionRestrict) return null + + if (!isRegionAllow) { + return ( undefined} variant="contained" size="large" className={classes.actionButton}> - {t('plugin_ito_unlock_in_advance')} + {t('plugin_ito_region_ban')} - - {shareText ? ( - - - {t('plugin_ito_share')} - - - ) : undefined} - - ) : listOfStatus.includes(ITO_Status.started) ? ( - - + ) + } + + if ( + (noRemain || listOfStatus.includes(ITO_Status.expired)) && + !canWithdraw && + ((availability?.claimed && hasLockTime) || !hasLockTime) + ) { + return null + } + + if (loadingTradeInfo || loadingAvailability) { + return ( undefined} variant="contained" size="large" className={classes.actionButton}> - {t('plugin_ito_enter')} + {t('plugin_ito_loading')} - - + ) + } + + if (!account || !chainIdValid) { + return ( - {t('plugin_ito_share')} + {t('plugin_wallet_connect_a_wallet')} - - - ) : null} + ) + } + + if (isBuyer) return FooterBuyerButton + + if (canWithdraw) { + return ( + + {t('plugin_ito_withdraw')} + + ) + } + + if ( + (!ifQualified || !(ifQualified as Qual_V2).qualified) && + !isNativeTokenAddress(qualificationAddress) + ) { + return ( + + {loadingIfQualified + ? t('plugin_ito_qualification_loading') + : !ifQualified + ? t('plugin_ito_qualification_failed') + : !(ifQualified as Qual_V2).qualified + ? startCase((ifQualified as Qual_V2).errorMsg) + : null} + + ) + } + + if (listOfStatus.includes(ITO_Status.expired)) return null + + if (listOfStatus.includes(ITO_Status.waited)) { + return ( + + + + {t('plugin_ito_unlock_in_advance')} + + + {shareText ? ( + + + {t('plugin_ito_share')} + + + ) : undefined} + + ) + } + + if (listOfStatus.includes(ITO_Status.started)) { + return ( + + + + {t('plugin_ito_enter')} + + + + + {t('plugin_ito_share')} + + + + ) + } + + return null + })()} Date: Fri, 25 Mar 2022 13:29:59 +0800 Subject: [PATCH 17/42] docs: update docs (#5954) * docs: update docs * fix: typo * fix: typo * docs: update docs --- .github/workflows/linters.yml | 2 +- docs/FAQ.md | 103 +++++++++++++++++++++++++++++++++ docs/setup.md | 104 ++++++++++++++++++++++++++++++++++ package.json | 2 +- 4 files changed, 209 insertions(+), 2 deletions(-) create mode 100644 docs/FAQ.md create mode 100644 docs/setup.md diff --git a/.github/workflows/linters.yml b/.github/workflows/linters.yml index 01ee5807c6be..fff8d66a95f7 100644 --- a/.github/workflows/linters.yml +++ b/.github/workflows/linters.yml @@ -21,7 +21,7 @@ jobs: with: ref: ${{ github.event.pull_request.head.sha }} - uses: actions/setup-node@v2 - - run: npx prettier@2.5.0 --check . + - run: npx prettier@2.6.0 --check . markdownlint: runs-on: ubuntu-20.04 steps: diff --git a/docs/FAQ.md b/docs/FAQ.md new file mode 100644 index 000000000000..543bef8d0847 --- /dev/null +++ b/docs/FAQ.md @@ -0,0 +1,103 @@ +# FAQ + +## How to resolve merge conflicts in `pnpm-lock.yaml`? + +Merge the target branch into yours and never mind those conflicts in `pnpm-lock.yaml`. And checkout the file to be the one on the target branch to revert changes your branch took in. Then run `pnpm install` to up the lockfile to date. + +E.g., your `feat/fantasy` branch conflicts with `develop` branch. + +```bash +> git branch --show-current +feat/fantasy + +# merge the develop branch and never manually handle the conflicts in lock file +> git merge develop + +# check out the lock file from the base branch +> git checkout develop -- pnpm-lock.yaml + +# up the lockfile to date +> pnpm install +``` + +## Why my Git hooks don't work? + +```bash +npx husky install # on project root directory +``` + +## How to fix cspell errors in CI? + +This project uses [cspell](https://github.com/streetsidesoftware/cspell) for checking typos. You can add unlisted words into `cspell.json` to bypass cspell checking. After you update the configuration file, you could run checking locally before pushing it to make sure your patch is working. + +```bash +npx cspell lint pattern_that_match_your_files + +# e.g. check spell of the RSS3 plugin +npx cspell lint ./packages/plugins/RSS3/**/* +``` + +Learn more: [`cspell.json`](https://cspell.org/configuration/#cspelljson) + +## Why were my components rendered many times? + +All components should working in [Strict Mode](https://reactjs.org/docs/strict-mode.html) and React 18 new [Strict Effects](https://github.com/reactwg/react-18/discussions/19). + +If you found your code not working correctly, please read the documentation above. In addition, you can comment out `` temporarily to verify if it is a problem with your component not supporting Strict Mode. + +DO NOT remove ``. + +## How to download CI builds? + +| Name | Description | +| ----------------------------- | ----------------------------------------------------------------------- | +| MaskNetwork.base.zip | The default build, currently is the same as the Chromium build. | +| MaskNetwork.chromium-beta.zip | Build for Chromium based browsers with some insider features turned on. | +| MaskNetwork.chromium.zip | Build for Chromium based browsers | +| MaskNetwork.firefox.zip | Build for Firefox | +| MaskNetwork.gecko.zip | Build for Android native Mask app | +| MaskNetwork.iOS.zip | Build for iOS native Mask app | + +You can download these builds in two places. + +- Github: Open the pull request page, and click the **Actions** tab. Then on the opened page, click the **build** sub-item on the **Compile** item. On the action detailed page, click the **Summary** tab. Now you can download builds on the **Artifacts** section. + + E.g., + +- CircleCI: Open the pull request page, and scroll down to the review status card. Click **Show all checks** to find the ** + ci/circleci: build** item, and click the **details** link. On the opened CircleCI page, click the **ARTIFACTS** tab. + + E.g., + +## How to resolve "No CORS Headers" problem + +Please contact the service maintainer to add CORS headers, the extension will send requests in following origins: + +| Browser | Origin | +| -------- | --------------------------------------------------- | +| Chromium | chrome-extension://jkoeaghipilijlahjplgbfiocjhldnap | +| Firefox | moz-extension://id | + +The Chromium extension has a fixed id, but only on production mode. And the Firefox browser will set a new id each time it boots an extension. So, in summary, it's better to allow all origins which match the regexp below. + +```txt +/.*-extension:\/\/[^\S]+/ +``` + +If you cannot reach the service maintainer another workaround is to use a proxy server to add CORS headers. To enable it try to change the request URL into `https://cors.r2d2.to/?=[url]`. + +```ts +// before +fetch('https://api.com') + +// after +fetch('https://cors.r2d2.to/?=https://api.com') +``` + +## How to clear the local settings? + +Open the background.html of the extension and execute the following scripts in the console. + +```js +browser.storage.local.clear() +``` diff --git a/docs/setup.md b/docs/setup.md new file mode 100644 index 000000000000..e85f6b6652de --- /dev/null +++ b/docs/setup.md @@ -0,0 +1,104 @@ +# Setup + +Hi, Welcome to the Mask Network. This guide will quickly take you through setting up the extension development environment. + +## Requirements + +Here is a snippet of engines requirements in the [`package.json`](../package.json) of Mask Network. As you can see, `NodeJS` and `pnpm` are required at least a specific version. + +We suggest you to use the latest Node.js version, and enable [corepack](https://nodejs.org/api/corepack.html). + +## Install + +### pnpm + +The [pnpm](https://pnpm.io/) is a disk space-efficient package manager. After NodeJS is preinstalled. + +If you have [corepack](https://nodejs.org/api/corepack.html) enabled, you can skip the `pnpm` section, `pnpm` is already available! + +If you want to setup pnpm manually, here is the [installation guide from pnpm](https://pnpm.io/installation). + +Now, you will need to have tools installed to start development. + +```bash +pnpm install +``` + +> If you encounter with error `EACCES: permission denied, open...'`, please run `chown -R $USER /pathToYourProject/Mask` to solve. + +### Start the local development server + +For Chromium-based browsers (Chrome, Opera, Edge, etc.), please run `pnpm start`. It's preset of many development commands. + +If you need to develop in other environments (for example, Firefox), please run `npx dev --help` to see the documentation. + +### Load the extension into your browser + +Mask Network has a huge codebase, and it might take time to let the webpack fully startup. It outcomes the `disk/` folder, which contains the unpacked source files of a development version of the Mask Network extension. + +For Chrome, + +- Open `chrome://extensions` or `Settings -> Extensions`. +- Turn on the `Developer mode` on the top right corner. +- It will present a top toolbar with an action button `Load unpacked` on it. Click it and choose the `dist/` folder to load the unpacked version of the Mask Network extension. You can drag and drop the `dist` folder into this page. +- If everything goes fine. Then, the Mask Network will guide you to the setup process. + +For Firefox, it's quite the same process. + +- Open `about:debugging#/runtime/this-firefox` +- Click the `Load Temporary Add-on…` and select the `dist/` folder to load the unpacked extension. +- If everything goes fine. The Mask Network will start to guide you to the setup process. + +## Debugging + +There is no difference between extension development and normal web development. In normal web development, you only have a single web page (SPA), but an extension could have more than one page. + +There is an invisible "background page" running all the time and an "options page" like a normal web page. Moreover, an extension could inject "content script" into the currently visiting web page. + +### Debug the background page + +The background page of the Mask Network extension maintains a bunch of fundamental services for front-end functions. Like Crypto Algorithm, Web3 SDKs, APIs to many third-party data providers, etc. They are stand-by all the time, once to be called for a specific task. + +To debug _background service_, click links right after **Inspect views**. + +![An image displaying Chrome extension manage page](https://user-images.githubusercontent.com/5390719/103509131-5ce0cb00-4e9d-11eb-9aec-b24b9888b863.png) + +### Debug the content script + +Mask Network only injects content script with permission from the user. + +For every new website that Mask Network is going to support, it will show a prompt dialog to ask permission dynamically, rather than asking for all permission when the plugin is installed. + +![An image displaying the Mask Network is asking the permission from the user](https://user-images.githubusercontent.com/52657989/158566232-30c52a17-0168-488c-a292-4fc4059ecb9c.png) + +To debug _content script_, open the dev tools in the web page, then you can select context as the following picture describes. + +![An image displaying how to select Mask Network as the debug context](https://user-images.githubusercontent.com/5390719/103509436-1a6bbe00-4e9e-11eb-9b18-bde021337944.png) + +It's important to select the correct context when you're debugging, +otherwise, you cannot access all the global variables, +_save as temp variables_ also fails. + +### Use React Devtools + +Run the following command to start the React Devtools. It doesn't work if you install it as a browser extension. + +> pnpx react-devtools + +And start the development by the following command: + +> pnpx dev --profile + +## Contribute your working + +### Git conversions + +The `develop` branch is our developing branch, and the `released` branch points to the latest released version. + +Your commit message should follow [Conventional Commits](https://www.conventionalcommits.org). + +### Using Git + +- [Using git rebase on the command line](https://docs.github.com/en/github/getting-started-with-github/using-git-rebase-on-the-command-line) +- [Configuring a remote for a fork](https://docs.github.com/en/github/collaborating-with-issues-and-pull-requests/configuring-a-remote-for-a-fork) +- [Syncing a fork](https://docs.github.com/en/github/collaborating-with-issues-and-pull-requests) diff --git a/package.json b/package.json index 974cdb360adf..30cdea4cdc89 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "mask-network", "packageManager": "pnpm@6.32.2", "engines": { - "node": ">=16.0.0", + "node": ">=17.0.0", "pnpm": ">=6.32.1", "we-only-allow-pnpm-in-our-project": ">=999.0.0", "yarn": ">=999.0.0", From 4d4daa77ac85db34f928c956f5de6a2a82c7e3b6 Mon Sep 17 00:00:00 2001 From: Jack Works Date: Mon, 21 Mar 2022 22:31:53 +0800 Subject: [PATCH 18/42] feat: move gun out of webpack compile (#5917) From 7a226dcaf3b6696742f8da2961778e4cb40d2b31 Mon Sep 17 00:00:00 2001 From: Lantt Date: Thu, 31 Mar 2022 12:35:55 +0800 Subject: [PATCH 19/42] feat: create next kv server api (#5994) * feat: create next kv server api * fix: cspell * fix: cspell * refactor: expose proof method by class * feat: add mask plugin key * refactor: create constants * fix: rename kv payload to storage payload --- .../Personas/hooks/useOperateBindingProof.ts | 18 +- .../pages/Personas/hooks/usePersonaProof.ts | 4 +- .../src/components/DataSource/useNextID.ts | 8 +- .../InjectedComponents/SetupGuide.tsx | 12 +- .../background-script/IdentityService.ts | 4 +- .../Personas/components/ProfileList/index.tsx | 6 +- .../plugins/NextID/components/BindDialog.tsx | 4 +- .../plugins/NextID/components/NextIdPage.tsx | 10 +- .../NextID/components/Tip/TipButton.tsx | 6 +- .../NextID/components/UnbindDialog.tsx | 4 +- .../plugins/NextID/hooks/useBindPayload.ts | 4 +- packages/shared-base/src/NextID/type.ts | 8 + .../web3-providers/src/NextID/constants.ts | 5 + packages/web3-providers/src/NextID/helper.ts | 40 ++++ packages/web3-providers/src/NextID/index.ts | 180 +----------------- packages/web3-providers/src/NextID/kv.ts | 111 +++++++++++ packages/web3-providers/src/NextID/proof.ts | 137 +++++++++++++ packages/web3-providers/src/index.ts | 3 + packages/web3-providers/src/types.ts | 57 ++++++ 19 files changed, 409 insertions(+), 212 deletions(-) create mode 100644 packages/web3-providers/src/NextID/constants.ts create mode 100644 packages/web3-providers/src/NextID/helper.ts create mode 100644 packages/web3-providers/src/NextID/kv.ts create mode 100644 packages/web3-providers/src/NextID/proof.ts diff --git a/packages/dashboard/src/pages/Personas/hooks/useOperateBindingProof.ts b/packages/dashboard/src/pages/Personas/hooks/useOperateBindingProof.ts index becfc6857449..7815f6f1ee1e 100644 --- a/packages/dashboard/src/pages/Personas/hooks/useOperateBindingProof.ts +++ b/packages/dashboard/src/pages/Personas/hooks/useOperateBindingProof.ts @@ -1,5 +1,5 @@ import { ECKeyIdentifier, NextIDPlatform } from '@masknet/shared-base' -import { bindProof, createPersonaPayload } from '@masknet/web3-providers' +import { NextIDProof } from '@masknet/web3-providers' import { useAsyncFn } from 'react-use' import { Services, Messages } from '../../../API' @@ -9,7 +9,7 @@ export function useDeleteBound() { const username = profile.userId.toLowerCase() const platform = network.split('.')[0] || NextIDPlatform.Twitter if (!persona_ || !persona_.publicHexKey) throw new Error('Failed to get person') - const payload = await createPersonaPayload(persona_.publicHexKey, action, username, platform) + const payload = await NextIDProof.createPersonaPayload(persona_.publicHexKey, action, username, platform) if (!payload) throw new Error('Failed to create persona payload.') const signResult = await Services.Identity.signWithPersona({ method: 'eth', @@ -18,9 +18,17 @@ export function useDeleteBound() { }) if (!signResult) throw new Error('Failed to sign by persona.') const signature = signResult.signature.signature - await bindProof(payload.uuid, persona_.publicHexKey, action, platform, username, payload.createdAt, { - signature: signature, - }) + await NextIDProof.bindProof( + payload.uuid, + persona_.publicHexKey, + action, + platform, + username, + payload.createdAt, + { + signature: signature, + }, + ) Services.Identity.detachProfile(profile) Messages.events.ownProofChanged.sendToAll(undefined) }) diff --git a/packages/dashboard/src/pages/Personas/hooks/usePersonaProof.ts b/packages/dashboard/src/pages/Personas/hooks/usePersonaProof.ts index 845204bdcdb1..d87ba3d025fd 100644 --- a/packages/dashboard/src/pages/Personas/hooks/usePersonaProof.ts +++ b/packages/dashboard/src/pages/Personas/hooks/usePersonaProof.ts @@ -1,11 +1,11 @@ -import { queryExistedBindingByPersona } from '@masknet/web3-providers' +import { NextIDProof } from '@masknet/web3-providers' import { useEffect } from 'react' import { useAsyncRetry } from 'react-use' import { Messages } from '../../../API' export function usePersonaProof(publicHexKey: string) { const res = useAsyncRetry(async () => { - return queryExistedBindingByPersona(publicHexKey) + return NextIDProof.queryExistedBindingByPersona(publicHexKey) }, [publicHexKey]) useEffect(() => Messages.events.ownProofChanged.on(res.retry), [res.retry]) return res diff --git a/packages/mask/src/components/DataSource/useNextID.ts b/packages/mask/src/components/DataSource/useNextID.ts index 9537838e36b9..ac19ace0ae2e 100644 --- a/packages/mask/src/components/DataSource/useNextID.ts +++ b/packages/mask/src/components/DataSource/useNextID.ts @@ -9,13 +9,13 @@ import { SetupGuideStep } from '../InjectedComponents/SetupGuide/types' import type { SetupGuideCrossContextStatus } from '../../settings/types' import { useLastRecognizedIdentity } from './useActivatedUI' import { useValueRef } from '@masknet/shared-base-ui' -import { queryExistedBindingByPersona, queryExistedBindingByPlatform, queryIsBound } from '@masknet/web3-providers' +import { NextIDProof } from '@masknet/web3-providers' import Services from '../../extension/service' import { MaskMessages } from '../../utils' export const usePersonaBoundPlatform = (personaPublicKey: string) => { return useAsyncRetry(() => { - return queryExistedBindingByPersona(personaPublicKey) + return NextIDProof.queryExistedBindingByPersona(personaPublicKey) }, [personaPublicKey]) } @@ -33,7 +33,7 @@ const verifyPersona = (personaIdentifier?: PersonaIdentifier, username?: string) export const useNextIDBoundByPlatform = (platform: NextIDPlatform, identity: string) => { const res = useAsyncRetry(() => { - return queryExistedBindingByPlatform(platform, identity) + return NextIDProof.queryExistedBindingByPlatform(platform, identity) }, [platform, identity]) useEffect(() => MaskMessages.events.ownProofChanged.on(res.retry), [res.retry]) return res @@ -99,7 +99,7 @@ export function useNextIDConnectStatus() { const platform = ui.configuration.nextIDConfig?.platform as NextIDPlatform | undefined if (!platform) return NextIDVerificationStatus.Other - const isBound = await queryIsBound(currentConnectedPersona.publicHexKey, platform, username) + const isBound = await NextIDProof.queryIsBound(currentConnectedPersona.publicHexKey, platform, username) if (isBound) return NextIDVerificationStatus.Verified if (isOpenedFromButton) { diff --git a/packages/mask/src/components/InjectedComponents/SetupGuide.tsx b/packages/mask/src/components/InjectedComponents/SetupGuide.tsx index 4122decacfec..d05d309b1703 100644 --- a/packages/mask/src/components/InjectedComponents/SetupGuide.tsx +++ b/packages/mask/src/components/InjectedComponents/SetupGuide.tsx @@ -26,7 +26,7 @@ import { SetupGuideStep } from './SetupGuide/types' import { FindUsername } from './SetupGuide/FindUsername' import { VerifyNextID } from './SetupGuide/VerifyNextID' import { PinExtension } from './SetupGuide/PinExtension' -import { bindProof, createPersonaPayload, queryIsBound } from '@masknet/web3-providers' +import { NextIDProof } from '@masknet/web3-providers' // #region setup guide ui interface SetupGuideUIProps { @@ -126,9 +126,9 @@ function SetupGuideUI(props: SetupGuideUIProps) { const platform = ui.configuration.nextIDConfig?.platform as NextIDPlatform | undefined if (!platform) return - const isBound = await queryIsBound(persona_.publicHexKey, platform, username) + const isBound = await NextIDProof.queryIsBound(persona_.publicHexKey, platform, username) if (!isBound) { - const payload = await createPersonaPayload( + const payload = await NextIDProof.createPersonaPayload( persona_.publicHexKey, NextIDAction.Create, username, @@ -151,7 +151,7 @@ function SetupGuideUI(props: SetupGuideUIProps) { const post = collectVerificationPost?.(postContent) if (post && persona_.publicHexKey) { clearInterval(verifyPostCollectTimer.current!) - await bindProof( + await NextIDProof.bindProof( payload.uuid, persona_.publicHexKey, NextIDAction.Create, @@ -174,7 +174,7 @@ function SetupGuideUI(props: SetupGuideUIProps) { }) await waitingPost - const isBound = await queryIsBound(persona_.publicHexKey, platform, username) + const isBound = await NextIDProof.queryIsBound(persona_.publicHexKey, platform, username) if (!isBound) throw new Error('Failed to verify.') MaskMessages.events.ownProofChanged.sendToAll(undefined) } @@ -187,7 +187,7 @@ function SetupGuideUI(props: SetupGuideUIProps) { const onConnected = async () => { if (enableNextID && persona_?.publicHexKey && platform && username) { - const isBound = await queryIsBound(persona_.publicHexKey, platform, username) + const isBound = await NextIDProof.queryIsBound(persona_.publicHexKey, platform, username) if (!isBound) { currentSetupGuideStatus[ui.networkIdentifier].value = stringify({ status: SetupGuideStep.VerifyOnNextID, diff --git a/packages/mask/src/extension/background-script/IdentityService.ts b/packages/mask/src/extension/background-script/IdentityService.ts index 9668da327efb..ba1095534d49 100644 --- a/packages/mask/src/extension/background-script/IdentityService.ts +++ b/packages/mask/src/extension/background-script/IdentityService.ts @@ -58,7 +58,7 @@ import { getCurrentPersonaIdentifier } from './SettingsService' import { MaskMessages } from '../../utils' import { first, orderBy } from 'lodash-unified' import { recover_ECDH_256k1_KeyPair_ByMnemonicWord } from '../../utils/mnemonic-code' -import { bindProof } from '@masknet/web3-providers' +import { NextIDProof } from '@masknet/web3-providers' assertEnvironment(Environment.ManifestBackground) @@ -406,7 +406,7 @@ export async function detachProfileWithNextID( proofLocation?: string }, ) { - await bindProof(uuid, personaPublicKey, NextIDAction.Delete, platform, identity, createdAt, { + await NextIDProof.bindProof(uuid, personaPublicKey, NextIDAction.Delete, platform, identity, createdAt, { signature: options?.signature, }) MaskMessages.events.ownProofChanged.sendToAll(undefined) diff --git a/packages/mask/src/extension/popups/pages/Personas/components/ProfileList/index.tsx b/packages/mask/src/extension/popups/pages/Personas/components/ProfileList/index.tsx index e06e71a181e2..e946b430fdfe 100644 --- a/packages/mask/src/extension/popups/pages/Personas/components/ProfileList/index.tsx +++ b/packages/mask/src/extension/popups/pages/Personas/components/ProfileList/index.tsx @@ -18,7 +18,7 @@ import { useAsyncFn, useAsyncRetry } from 'react-use' import Services from '../../../../../service' import { GrayMasks } from '@masknet/icons' import { DisconnectDialog } from '../DisconnectDialog' -import { createPersonaPayload, queryExistedBindingByPersona } from '@masknet/web3-providers' +import { NextIDProof } from '@masknet/web3-providers' import classNames from 'classnames' import { useNavigate } from 'react-router-dom' import urlcat from 'urlcat' @@ -151,7 +151,7 @@ export const ProfileList = memo(() => { const { value: mergedProfiles, retry: refreshProfileList } = useAsyncRetry(async () => { if (!currentPersona) return [] if (!currentPersona.publicHexKey) return currentPersona.linkedProfiles - const response = await queryExistedBindingByPersona(currentPersona.publicHexKey) + const response = await NextIDProof.queryExistedBindingByPersona(currentPersona.publicHexKey) if (!response) return currentPersona.linkedProfiles return currentPersona.linkedProfiles.map((profile) => { @@ -177,7 +177,7 @@ export const ProfileList = memo(() => { const publicHexKey = currentPersona.publicHexKey if (!publicHexKey || !unbind || !unbind.identity || !unbind.platform) return - const result = await createPersonaPayload( + const result = await NextIDProof.createPersonaPayload( publicHexKey, NextIDAction.Delete, unbind.identity, diff --git a/packages/mask/src/plugins/NextID/components/BindDialog.tsx b/packages/mask/src/plugins/NextID/components/BindDialog.tsx index 525e608bc341..e5e3698a0a94 100644 --- a/packages/mask/src/plugins/NextID/components/BindDialog.tsx +++ b/packages/mask/src/plugins/NextID/components/BindDialog.tsx @@ -12,7 +12,7 @@ import { delay } from '@dimensiondev/kit' import { useBindPayload } from '../hooks/useBindPayload' import { usePersonaSign } from '../hooks/usePersonaSign' import { useWalletSign } from '../hooks/useWalletSign' -import { bindProof } from '@masknet/web3-providers' +import { NextIDProof } from '@masknet/web3-providers' interface BindDialogProps { open: boolean @@ -36,7 +36,7 @@ export const BindDialog = memo(({ open, onClose, persona, onBou useAsyncRetry(async () => { if (!personaSignState.value || !walletSignState.value || isBound || !message || !persona.publicHexKey) return try { - await bindProof( + await NextIDProof.bindProof( message.uuid, persona.publicHexKey, NextIDAction.Create, diff --git a/packages/mask/src/plugins/NextID/components/NextIdPage.tsx b/packages/mask/src/plugins/NextID/components/NextIdPage.tsx index 12a63395ffb9..96d7281e1ce5 100644 --- a/packages/mask/src/plugins/NextID/components/NextIdPage.tsx +++ b/packages/mask/src/plugins/NextID/components/NextIdPage.tsx @@ -1,6 +1,6 @@ import { NextIDPlatform } from '@masknet/shared-base' import { makeStyles } from '@masknet/theme' -import { queryExistedBindingByPersona, queryIsBound } from '@masknet/web3-providers' +import { NextIDProof } from '@masknet/web3-providers' import { Box, Button, Skeleton, Stack, Typography } from '@mui/material' import { useMemo, useState } from 'react' import { useAsync, useAsyncRetry } from 'react-use' @@ -83,7 +83,11 @@ export function NextIdPage({ personaList }: NextIDPageProps) { const { value: isAccountVerified, loading: loadingVerifyInfo } = useAsync(async () => { if (!currentPersona?.publicHexKey) return - return queryIsBound(currentPersona.publicHexKey, platform, visitingPersonaIdentifier.identifier.userId) + return NextIDProof.queryIsBound( + currentPersona.publicHexKey, + platform, + visitingPersonaIdentifier.identifier.userId, + ) }, [isOwn, currentPersona, visitingPersonaIdentifier, isVerified]) const { @@ -92,7 +96,7 @@ export function NextIdPage({ personaList }: NextIDPageProps) { retry: retryQueryBinding, } = useAsyncRetry(async () => { if (!currentPersona) return - return queryExistedBindingByPersona(currentPersona.publicHexKey!) + return NextIDProof.queryExistedBindingByPersona(currentPersona.publicHexKey!) }, [currentPersona, isOwn]) const onVerify = async () => { diff --git a/packages/mask/src/plugins/NextID/components/Tip/TipButton.tsx b/packages/mask/src/plugins/NextID/components/Tip/TipButton.tsx index 587c4c52f96b..04daf94ccd45 100644 --- a/packages/mask/src/plugins/NextID/components/Tip/TipButton.tsx +++ b/packages/mask/src/plugins/NextID/components/Tip/TipButton.tsx @@ -2,7 +2,7 @@ import { TipCoin } from '@masknet/icons' import { usePostInfoDetails } from '@masknet/plugin-infra' import { NextIDPlatform, ProfileIdentifier } from '@masknet/shared-base' import { makeStyles, ShadowRootTooltip } from '@masknet/theme' -import { queryExistedBindingByPersona, queryIsBound } from '@masknet/web3-providers' +import { NextIDProof } from '@masknet/web3-providers' import { EMPTY_LIST } from '@masknet/web3-shared-evm' import type { TooltipProps } from '@mui/material' import classnames from 'classnames' @@ -74,7 +74,7 @@ export const TipButton: FC = ({ const { value: isAccountVerified, loading: loadingVerifyInfo } = useAsync(() => { if (!receiverPersona?.publicHexKey || !receiver?.userId) return Promise.resolve(false) - return queryIsBound(receiverPersona.publicHexKey, platform, receiver.userId, true) + return NextIDProof.queryIsBound(receiverPersona.publicHexKey, platform, receiver.userId, true) }, [receiverPersona?.publicHexKey, platform, receiver?.userId]) const [walletsState, queryBindings] = useAsyncFn(async () => { @@ -83,7 +83,7 @@ export const TipButton: FC = ({ const persona = await Services.Identity.queryPersonaByProfile(receiver) if (!persona?.publicHexKey) return EMPTY_LIST - const bindings = await queryExistedBindingByPersona(persona.publicHexKey, true) + const bindings = await NextIDProof.queryExistedBindingByPersona(persona.publicHexKey, true) if (!bindings) return EMPTY_LIST const wallets = bindings.proofs.filter((p) => p.platform === NextIDPlatform.Ethereum).map((p) => p.identity) diff --git a/packages/mask/src/plugins/NextID/components/UnbindDialog.tsx b/packages/mask/src/plugins/NextID/components/UnbindDialog.tsx index 16f8b9a498d9..aadc5dc1cf72 100644 --- a/packages/mask/src/plugins/NextID/components/UnbindDialog.tsx +++ b/packages/mask/src/plugins/NextID/components/UnbindDialog.tsx @@ -12,7 +12,7 @@ import { useBindPayload } from '../hooks/useBindPayload' import { delay } from '@dimensiondev/kit' import { UnbindPanelUI } from './UnbindPanelUI' import { UnbindConfirm } from './UnbindConfirm' -import { bindProof } from '@masknet/web3-providers' +import { NextIDProof } from '@masknet/web3-providers' interface VerifyWalletDialogProps { unbindAddress: string @@ -40,7 +40,7 @@ export const UnbindDialog = memo(({ unbindAddress, onCl if (!personaSignState.value && !walletSignState.value) return if (!message || !persona.publicHexKey) return try { - await bindProof( + await NextIDProof.bindProof( message.uuid, persona.publicHexKey, NextIDAction.Delete, diff --git a/packages/mask/src/plugins/NextID/hooks/useBindPayload.ts b/packages/mask/src/plugins/NextID/hooks/useBindPayload.ts index b995a4577f79..8ae719362503 100644 --- a/packages/mask/src/plugins/NextID/hooks/useBindPayload.ts +++ b/packages/mask/src/plugins/NextID/hooks/useBindPayload.ts @@ -1,11 +1,11 @@ import { useAsyncRetry } from 'react-use' -import { createPersonaPayload } from '@masknet/web3-providers' +import { NextIDProof } from '@masknet/web3-providers' import { NextIDAction, NextIDPlatform } from '@masknet/shared-base' export const useBindPayload = (action: NextIDAction, address?: string, currentIdentifier?: string) => { return useAsyncRetry(() => { if (!address) return Promise.resolve(undefined) if (!currentIdentifier || !address) return Promise.resolve(undefined) - return createPersonaPayload(currentIdentifier, action, address, NextIDPlatform.Ethereum) + return NextIDProof.createPersonaPayload(currentIdentifier, action, address, NextIDPlatform.Ethereum) }, [currentIdentifier, address]) } diff --git a/packages/shared-base/src/NextID/type.ts b/packages/shared-base/src/NextID/type.ts index d5e4bea4334f..fa093d58324f 100644 --- a/packages/shared-base/src/NextID/type.ts +++ b/packages/shared-base/src/NextID/type.ts @@ -48,3 +48,11 @@ export interface NextIDBindings { pagination: Pagination ids: NextIDPersonaBindings[] } + +// #region kv server +export interface NextIDStoragePayload { + uuid: string + signPayload: string + createdAt: string +} +// #endregion diff --git a/packages/web3-providers/src/NextID/constants.ts b/packages/web3-providers/src/NextID/constants.ts new file mode 100644 index 000000000000..ccaf51f87774 --- /dev/null +++ b/packages/web3-providers/src/NextID/constants.ts @@ -0,0 +1,5 @@ +export const MASK_STORAGE_KEY = 'com.mask.plugin' +export const KV_BASE_URL_DEV = 'https://kv-service.nextnext.id' +export const KV_BASE_URL_PROD = '' +export const PROOF_BASE_URL_DEV = 'https://proof-service.nextnext.id/' +export const PROOF_BASE_URL_PROD = 'https://proof-service.next.id/' diff --git a/packages/web3-providers/src/NextID/helper.ts b/packages/web3-providers/src/NextID/helper.ts new file mode 100644 index 000000000000..560e3c9d8363 --- /dev/null +++ b/packages/web3-providers/src/NextID/helper.ts @@ -0,0 +1,40 @@ +import LRU from 'lru-cache' +import { Result, Ok, Err } from 'ts-results' + +const fetchCache = new LRU({ + max: 100, + ttl: 20000, +}) + +export async function fetchJSON( + url: string, + requestInit?: RequestInit, + enableCache?: boolean, +): Promise> { + type FetchCache = LRU | T> + + const cached = enableCache ? (fetchCache as FetchCache).get(url) : undefined + const isPending = cached instanceof Promise + if (cached && !isPending) { + return Ok(cached) + } + let pendingResponse: Promise + if (isPending) { + pendingResponse = cached + } else { + pendingResponse = globalThis.fetch(url, { mode: 'cors', ...requestInit }) + if (enableCache) { + fetchCache.set(url, pendingResponse) + } + } + const response = await pendingResponse + + const result = await response.clone().json() + + if (result.message || !response.ok) { + return Err(result.message) + } + fetchCache.set(url, result) + + return Ok(result) +} diff --git a/packages/web3-providers/src/NextID/index.ts b/packages/web3-providers/src/NextID/index.ts index 4167ff5f2600..d757a926156f 100644 --- a/packages/web3-providers/src/NextID/index.ts +++ b/packages/web3-providers/src/NextID/index.ts @@ -1,178 +1,2 @@ -import { - BindingProof, - fromHex, - NextIDAction, - NextIDBindings, - NextIDPayload, - NextIDPlatform, - toBase64, -} from '@masknet/shared-base' -import LRU from 'lru-cache' -import urlcat from 'urlcat' -import { first } from 'lodash-unified' - -const BASE_URL = - process.env.channel === 'stable' && process.env.NODE_ENV === 'production' - ? 'https://proof-service.next.id/' - : 'https://proof-service.nextnext.id/' - -interface CreatePayloadBody { - action: string - platform: string - identity: string - public_key: string -} - -type PostContentLanguages = 'default' | 'zh_CN' - -interface CreatePayloadResponse { - post_content: { [key in PostContentLanguages]: string } - sign_payload: string - uuid: string - created_at: string -} - -const fetchCache = new LRU({ - max: 100, - ttl: 20000, -}) - -export async function fetchJSON( - url: string, - requestInit?: RequestInit, - enableCache?: boolean, -): Promise { - type FetchCache = LRU | T> - - const cached = enableCache ? (fetchCache as FetchCache).get(url) : undefined - const isPending = cached instanceof Promise - if (cached && !isPending) { - return cached - } - let pendingResponse: Promise - if (isPending) { - pendingResponse = cached - } else { - pendingResponse = globalThis.fetch(url, { mode: 'cors', ...requestInit }) - if (enableCache) { - fetchCache.set(url, pendingResponse) - } - } - const response = await pendingResponse - - const result = await response.clone().json() - - if (result.message || !response.ok) { - throw new Error(result.message) - } - fetchCache.set(url, result) - return result -} - -// TODO: remove 'bind' in project for business context. -export async function bindProof( - uuid: string, - personaPublicKey: string, - action: NextIDAction, - platform: string, - identity: string, - createdAt: string, - options?: { - walletSignature?: string - signature?: string - proofLocation?: string - }, -) { - const requestBody = { - uuid, - action, - platform, - identity, - public_key: personaPublicKey, - proof_location: options?.proofLocation, - extra: { - wallet_signature: options?.walletSignature ? toBase64(fromHex(options.walletSignature)) : undefined, - signature: options?.signature ? toBase64(fromHex(options.signature)) : undefined, - }, - created_at: createdAt, - } - - return fetchJSON(urlcat(BASE_URL, '/v1/proof'), { - body: JSON.stringify(requestBody), - method: 'POST', - }) -} - -export async function queryExistedBindingByPersona(personaPublicKey: string, enableCache?: boolean) { - const response = await fetchJSON( - urlcat(BASE_URL, '/v1/proof', { platform: NextIDPlatform.NextId, identity: personaPublicKey }), - {}, - enableCache, - ) - // Will have only one item when query by personaPublicKey - return first(response.ids) -} - -export async function queryExistedBindingByPlatform(platform: NextIDPlatform, identity: string, page?: number) { - if (!platform && !identity) return [] - - const response = await fetchJSON( - urlcat(BASE_URL, '/v1/proof', { platform: platform, identity: identity }), - ) - - // TODO: merge Pagination into this - return response.ids -} - -export async function queryIsBound( - personaPublicKey: string, - platform: NextIDPlatform, - identity: string, - enableCache?: boolean, -) { - if (!platform && !identity) return false - - try { - await fetchJSON( - urlcat(BASE_URL, '/v1/proof/exists', { - platform: platform, - identity: identity, - public_key: personaPublicKey, - }), - {}, - enableCache, - ) - return true - } catch { - return false - } -} - -export async function createPersonaPayload( - personaPublicKey: string, - action: NextIDAction, - identity: string, - platform: NextIDPlatform, - language?: string, -): Promise { - const requestBody: CreatePayloadBody = { - action, - platform, - identity, - public_key: personaPublicKey, - } - - const nextIDLanguageFormat = language?.replace('-', '_') as PostContentLanguages - - const response = await fetchJSON(urlcat(BASE_URL, '/v1/proof/payload'), { - body: JSON.stringify(requestBody), - method: 'POST', - }) - - return { - postContent: response.post_content[nextIDLanguageFormat ?? 'default'] ?? response.post_content.default, - signPayload: JSON.stringify(JSON.parse(response.sign_payload)), - createdAt: response.created_at, - uuid: response.uuid, - } -} +export * from './kv' +export * from './proof' diff --git a/packages/web3-providers/src/NextID/kv.ts b/packages/web3-providers/src/NextID/kv.ts new file mode 100644 index 000000000000..3598383851d8 --- /dev/null +++ b/packages/web3-providers/src/NextID/kv.ts @@ -0,0 +1,111 @@ +/** + * Document url: https://github.com/nextdotid/kv_server/blob/develop/docs/api.apib + */ +import urlcat from 'urlcat' +import type { NextIDStoragePayload, NextIDPlatform } from '@masknet/shared-base' +import { fetchJSON } from './helper' +import type { Result } from 'ts-results' +import type { NextIDBaseAPI } from '../types' +import { KV_BASE_URL_DEV, KV_BASE_URL_PROD, MASK_STORAGE_KEY } from './constants' + +interface CreatePayloadResponse { + uuid: string + sign_payload: string + created_at: string +} + +const BASE_URL = + process.env.channel === 'stable' && process.env.NODE_ENV === 'production' ? KV_BASE_URL_PROD : KV_BASE_URL_DEV + +function formatPatchData(platform: NextIDPlatform, identity: string, data: unknown) { + return { + [MASK_STORAGE_KEY]: { + [`${platform}_${identity}`]: data, + }, + } +} + +export class NextIDStorageAPI implements NextIDBaseAPI.Storage { + /** + * Get current KV of a persona + * @param personaPublicKey + * + */ + async get(personaPublicKey: string): Promise> { + const full = await fetchJSON<{ [MASK_STORAGE_KEY]: T }>( + urlcat(BASE_URL, '/v1/kv', { persona: personaPublicKey }), + ) + return full.map((x) => x[MASK_STORAGE_KEY]) + } + + /** + * Get signature payload for updating + * @param personaPublicKey + * @param platform + * @param identity + * @param patchData + * + * We choose [RFC 7396](https://www.rfc-editor.org/rfc/rfc7396) standard for KV modifying. + */ + async getPayload( + personaPublicKey: string, + platform: NextIDPlatform, + identity: string, + patchData: unknown, + ): Promise> { + const requestBody = { + persona: personaPublicKey, + platform, + identity, + patch: formatPatchData(platform, identity, patchData), + } + + const response = await fetchJSON(urlcat(BASE_URL, '/v1/kv/payload'), { + body: JSON.stringify(requestBody), + method: 'POST', + }) + + return response.map((x) => ({ + signPayload: JSON.stringify(JSON.parse(x.sign_payload)), + createdAt: x.created_at, + uuid: x.uuid, + })) + } + + /** + * Update a full set of key-value pairs + * @param uuid + * @param personaPublicKey + * @param signature + * @param platform + * @param identity + * @param createdAt + * @param patchData + * + * We choose [RFC 7396](https://www.rfc-editor.org/rfc/rfc7396) standard for KV modifying. + */ + set( + uuid: string, + personaPublicKey: string, + signature: string, + platform: NextIDPlatform, + identity: string, + createdAt: string, + patchData: unknown, + ): Promise> { + const requestBody = { + uuid, + persona: personaPublicKey, + platform, + identity, + signature, + patch: formatPatchData(platform, identity, patchData), + created_at: createdAt, + } + + return fetchJSON(urlcat(BASE_URL, '/v1/kv'), { + body: JSON.stringify(requestBody), + method: 'POST', + }) + } +} diff --git a/packages/web3-providers/src/NextID/proof.ts b/packages/web3-providers/src/NextID/proof.ts new file mode 100644 index 000000000000..7f126278fce9 --- /dev/null +++ b/packages/web3-providers/src/NextID/proof.ts @@ -0,0 +1,137 @@ +import { fetchJSON } from './helper' +import urlcat from 'urlcat' +import { first } from 'lodash-unified' +import { + BindingProof, + fromHex, + NextIDAction, + NextIDBindings, + NextIDPayload, + NextIDPlatform, + toBase64, +} from '@masknet/shared-base' +import type { NextIDBaseAPI } from '../types' +import { PROOF_BASE_URL_DEV, PROOF_BASE_URL_PROD } from './constants' + +const BASE_URL = + process.env.channel === 'stable' && process.env.NODE_ENV === 'production' ? PROOF_BASE_URL_PROD : PROOF_BASE_URL_DEV + +interface CreatePayloadBody { + action: string + platform: string + identity: string + public_key: string +} + +type PostContentLanguages = 'default' | 'zh_CN' + +interface CreatePayloadResponse { + post_content: { [key in PostContentLanguages]: string } + sign_payload: string + uuid: string + created_at: string +} + +export class NextIDProofAPI implements NextIDBaseAPI.Proof { + // TODO: remove 'bind' in project for business context. + bindProof( + uuid: string, + personaPublicKey: string, + action: NextIDAction, + platform: string, + identity: string, + createdAt: string, + options?: { + walletSignature?: string + signature?: string + proofLocation?: string + }, + ) { + const requestBody = { + uuid, + action, + platform, + identity, + public_key: personaPublicKey, + proof_location: options?.proofLocation, + extra: { + wallet_signature: options?.walletSignature ? toBase64(fromHex(options.walletSignature)) : undefined, + signature: options?.signature ? toBase64(fromHex(options.signature)) : undefined, + }, + created_at: createdAt, + } + + return fetchJSON(urlcat(BASE_URL, '/v1/proof'), { + body: JSON.stringify(requestBody), + method: 'POST', + }) + } + + async queryExistedBindingByPersona(personaPublicKey: string, enableCache?: boolean) { + const response = await fetchJSON( + urlcat(BASE_URL, '/v1/proof', { platform: NextIDPlatform.NextId, identity: personaPublicKey }), + {}, + enableCache, + ) + // Will have only one item when query by personaPublicKey + return first(response.unwrap().ids) + } + + async queryExistedBindingByPlatform(platform: NextIDPlatform, identity: string, page?: number) { + if (!platform && !identity) return [] + + const response = await fetchJSON( + urlcat(BASE_URL, '/v1/proof', { platform: platform, identity: identity }), + ) + + // TODO: merge Pagination into this + return response.unwrap().ids + } + + async queryIsBound(personaPublicKey: string, platform: NextIDPlatform, identity: string, enableCache?: boolean) { + if (!platform && !identity) return false + + const result = await fetchJSON( + urlcat(BASE_URL, '/v1/proof/exists', { + platform: platform, + identity: identity, + public_key: personaPublicKey, + }), + {}, + enableCache, + ) + + return result.map(() => true).unwrapOr(false) + } + + async createPersonaPayload( + personaPublicKey: string, + action: NextIDAction, + identity: string, + platform: NextIDPlatform, + language?: string, + ): Promise { + const requestBody: CreatePayloadBody = { + action, + platform, + identity, + public_key: personaPublicKey, + } + + const nextIDLanguageFormat = language?.replace('-', '_') as PostContentLanguages + + const response = await fetchJSON(urlcat(BASE_URL, '/v1/proof/payload'), { + body: JSON.stringify(requestBody), + method: 'POST', + }) + + return response + .map((x) => ({ + postContent: x.post_content[nextIDLanguageFormat ?? 'default'] ?? x.post_content.default, + signPayload: JSON.stringify(JSON.parse(x.sign_payload)), + createdAt: x.created_at, + uuid: x.uuid, + })) + .unwrapOr(null) + } +} diff --git a/packages/web3-providers/src/index.ts b/packages/web3-providers/src/index.ts index d3989c5950fc..37dadc67dfc6 100644 --- a/packages/web3-providers/src/index.ts +++ b/packages/web3-providers/src/index.ts @@ -10,6 +10,7 @@ import { TwitterAPI } from './twitter' import { TokenListAPI } from './token-list' import { TokenPriceAPI } from './token-price' import { InstagramAPI } from './instagram' +import { NextIDProofAPI, NextIDStorageAPI } from './NextID' export * from './types' export * from './hooks' @@ -28,6 +29,8 @@ export const Twitter = new TwitterAPI() export const Instagram = new InstagramAPI() export const TokenList = new TokenListAPI() export const TokenPrice = new TokenPriceAPI() +export const NextIDStorage = new NextIDStorageAPI() +export const NextIDProof = new NextIDProofAPI() // Method for provider proxy export { getOpenSeaNFTList, getOpenSeaCollectionList } from './opensea' diff --git a/packages/web3-providers/src/types.ts b/packages/web3-providers/src/types.ts index 5e4a0def0320..32259fb1564e 100644 --- a/packages/web3-providers/src/types.ts +++ b/packages/web3-providers/src/types.ts @@ -8,6 +8,8 @@ import type { NativeTokenDetailed, } from '@masknet/web3-shared-evm' import type { CurrencyType } from '@masknet/plugin-infra' +import type { Result } from 'ts-results' +import type { NextIDAction, NextIDStoragePayload, NextIDPayload, NextIDPlatform } from '@masknet/shared-base' export namespace ExplorerAPI { export type Transaction = Web3Transaction & { @@ -308,6 +310,61 @@ export namespace StorageAPI { } } +export namespace NextIDBaseAPI { + export interface Storage { + set( + uuid: string, + personaPublicKey: string, + signature: string, + platform: NextIDPlatform, + identity: string, + createdAt: string, + patchData: unknown, + ): Promise> + get(key: string): Promise> + getPayload( + personaPublicKey: string, + platform: NextIDPlatform, + identity: string, + patchData: unknown, + ): Promise> + } + export interface Proof { + bindProof( + uuid: string, + personaPublicKey: string, + action: NextIDAction, + platform: string, + identity: string, + createdAt: string, + options?: { + walletSignature?: string + signature?: string + proofLocation?: string + }, + ): Promise> + + queryExistedBindingByPersona(personaPublicKey: string, enableCache?: boolean): Promise + + queryExistedBindingByPlatform(platform: NextIDPlatform, identity: string, page?: number): Promise + + queryIsBound( + personaPublicKey: string, + platform: NextIDPlatform, + identity: string, + enableCache?: boolean, + ): Promise + + createPersonaPayload( + personaPublicKey: string, + action: NextIDAction, + identity: string, + platform: NextIDPlatform, + language?: string, + ): Promise + } +} + export namespace SecurityAPI { export interface Holder { address?: string From ce098e848509c6a71f9635968cc6e8fae48fb6eb Mon Sep 17 00:00:00 2001 From: Lantt Date: Thu, 31 Mar 2022 15:16:17 +0800 Subject: [PATCH 20/42] feat: Go Plus Security plugin (#5873) * feat: go plus security plugin setup * feat: add get supported chain for go plus lab * feat: plugin frame step 1 * feat: add risk rules * feat: search box style * feat: panel layout * feat: panel style * feat: update i18n * feat: update rules * style: improve * style: interaction design improve * feat: add default safa item card * feat: all the field is optional * feat: use go plus lab url proxy * chore: lock file * feat: improve * fix: cspell * feat: link to explorer * chore: migrate mask message * feat: configurable app board * Revert "chore: migrate mask message" This reverts commit 817e433eee9ee5bbf894e14c657e7b6c5c1e99d9. * chore: resolve conflict * chore: resolve conflict * feat: open from application entry * feat: dialog background * feat: update base info * feat: footer goto go plus website * fix: order by risk * style: security panel height * refactor: create token panel component * feat: use transition for token info collapse * fix: should clear state when close dialog * fix: remove debug code * fix: rename network to chain * fix: feedback * style: dialog size * refactor: convert chain's id type from string to chain id * refactor: code review feedback * fix: should can be use when not connect wallet Co-authored-by: zhouhanseng Co-authored-by: guanbinrui <52657989+guanbinrui@users.noreply.github.com> --- .i18n-codegen.json | 12 + cspell.json | 2 + packages/icons/general/Risk.tsx | 4 +- packages/mask/.webpack/config.ts | 1 + packages/mask/package.json | 1 + packages/mask/src/plugin-infra/register.js | 1 + packages/plugin-infra/src/types.ts | 1 + packages/plugins/GoPlusSecurity/package.json | 20 ++ .../GoPlusSecurity/src/Dashboard/index.tsx | 9 + .../src/SNSAdaptor/CheckSecurityDialog.tsx | 86 ++++++ .../src/SNSAdaptor/components/Common.tsx | 52 ++++ .../components/DefaultPlaceholder.tsx | 17 ++ .../src/SNSAdaptor/components/Footer.tsx | 22 ++ .../src/SNSAdaptor/components/Loading.tsx | 22 ++ .../src/SNSAdaptor/components/NotFound.tsx | 13 + .../src/SNSAdaptor/components/RiskCard.tsx | 66 ++++ .../src/SNSAdaptor/components/SearchBox.tsx | 125 ++++++++ .../src/SNSAdaptor/components/Searching.tsx | 10 + .../SNSAdaptor/components/SecurityPanel.tsx | 148 +++++++++ .../src/SNSAdaptor/components/TokenPanel.tsx | 170 +++++++++++ .../src/SNSAdaptor/icons/Loading.tsx | 21 ++ .../src/SNSAdaptor/icons/Logo.tsx | 30 ++ .../src/SNSAdaptor/icons/SecurityIcon.tsx | 53 ++++ .../GoPlusSecurity/src/SNSAdaptor/index.tsx | 30 ++ .../GoPlusSecurity/src/SNSAdaptor/rules.ts | 283 ++++++++++++++++++ .../GoPlusSecurity/src/Worker/index.ts | 9 + .../src/assets/security-icon.png | Bin 0 -> 1721 bytes packages/plugins/GoPlusSecurity/src/base.ts | 17 ++ .../plugins/GoPlusSecurity/src/constants.ts | 7 + packages/plugins/GoPlusSecurity/src/env.d.ts | 1 + packages/plugins/GoPlusSecurity/src/index.ts | 23 ++ .../GoPlusSecurity/src/locales/en-US.json | 74 +++++ .../GoPlusSecurity/src/locales/index.ts | 6 + .../GoPlusSecurity/src/locales/ja-JP.json | 1 + .../GoPlusSecurity/src/locales/ko-KR.json | 1 + .../GoPlusSecurity/src/locales/languages.ts | 34 +++ .../GoPlusSecurity/src/locales/qya-AA.json | 1 + .../GoPlusSecurity/src/locales/zh-CN.json | 1 + .../GoPlusSecurity/src/locales/zh-TW.json | 1 + .../plugins/GoPlusSecurity/src/messages.ts | 13 + .../GoPlusSecurity/src/utils/helper.ts | 5 + packages/plugins/GoPlusSecurity/tsconfig.json | 10 + .../src/utils/requestComposition.ts | 10 + packages/shared/src/hooks/useMenu.tsx | 2 + .../src/gopluslabs/constants.ts | 2 +- .../web3-providers/src/gopluslabs/index.ts | 26 +- packages/web3-providers/src/index.ts | 3 + packages/web3-providers/src/types.ts | 43 ++- pnpm-lock.yaml | 30 ++ tsconfig.json | 1 + 50 files changed, 1504 insertions(+), 16 deletions(-) create mode 100644 packages/plugins/GoPlusSecurity/package.json create mode 100644 packages/plugins/GoPlusSecurity/src/Dashboard/index.tsx create mode 100644 packages/plugins/GoPlusSecurity/src/SNSAdaptor/CheckSecurityDialog.tsx create mode 100644 packages/plugins/GoPlusSecurity/src/SNSAdaptor/components/Common.tsx create mode 100644 packages/plugins/GoPlusSecurity/src/SNSAdaptor/components/DefaultPlaceholder.tsx create mode 100644 packages/plugins/GoPlusSecurity/src/SNSAdaptor/components/Footer.tsx create mode 100644 packages/plugins/GoPlusSecurity/src/SNSAdaptor/components/Loading.tsx create mode 100644 packages/plugins/GoPlusSecurity/src/SNSAdaptor/components/NotFound.tsx create mode 100644 packages/plugins/GoPlusSecurity/src/SNSAdaptor/components/RiskCard.tsx create mode 100644 packages/plugins/GoPlusSecurity/src/SNSAdaptor/components/SearchBox.tsx create mode 100644 packages/plugins/GoPlusSecurity/src/SNSAdaptor/components/Searching.tsx create mode 100644 packages/plugins/GoPlusSecurity/src/SNSAdaptor/components/SecurityPanel.tsx create mode 100644 packages/plugins/GoPlusSecurity/src/SNSAdaptor/components/TokenPanel.tsx create mode 100644 packages/plugins/GoPlusSecurity/src/SNSAdaptor/icons/Loading.tsx create mode 100644 packages/plugins/GoPlusSecurity/src/SNSAdaptor/icons/Logo.tsx create mode 100644 packages/plugins/GoPlusSecurity/src/SNSAdaptor/icons/SecurityIcon.tsx create mode 100644 packages/plugins/GoPlusSecurity/src/SNSAdaptor/index.tsx create mode 100644 packages/plugins/GoPlusSecurity/src/SNSAdaptor/rules.ts create mode 100644 packages/plugins/GoPlusSecurity/src/Worker/index.ts create mode 100644 packages/plugins/GoPlusSecurity/src/assets/security-icon.png create mode 100644 packages/plugins/GoPlusSecurity/src/base.ts create mode 100644 packages/plugins/GoPlusSecurity/src/constants.ts create mode 100644 packages/plugins/GoPlusSecurity/src/env.d.ts create mode 100644 packages/plugins/GoPlusSecurity/src/index.ts create mode 100644 packages/plugins/GoPlusSecurity/src/locales/en-US.json create mode 100644 packages/plugins/GoPlusSecurity/src/locales/index.ts create mode 100644 packages/plugins/GoPlusSecurity/src/locales/ja-JP.json create mode 100644 packages/plugins/GoPlusSecurity/src/locales/ko-KR.json create mode 100644 packages/plugins/GoPlusSecurity/src/locales/languages.ts create mode 100644 packages/plugins/GoPlusSecurity/src/locales/qya-AA.json create mode 100644 packages/plugins/GoPlusSecurity/src/locales/zh-CN.json create mode 100644 packages/plugins/GoPlusSecurity/src/locales/zh-TW.json create mode 100644 packages/plugins/GoPlusSecurity/src/messages.ts create mode 100644 packages/plugins/GoPlusSecurity/src/utils/helper.ts create mode 100644 packages/plugins/GoPlusSecurity/tsconfig.json create mode 100644 packages/shared-base/src/utils/requestComposition.ts diff --git a/.i18n-codegen.json b/.i18n-codegen.json index 0e88dbae02d2..cb999243cc8d 100644 --- a/.i18n-codegen.json +++ b/.i18n-codegen.json @@ -181,6 +181,18 @@ "trans": "Translate", "sourceMap": "inline" } + }, + { + "input": "./packages/plugins/GoPlusSecurity/src/locales/en-US.json", + "output": "./packages/plugins/GoPlusSecurity/src/locales/i18n_generated", + "parser": "i18next", + "generator": { + "type": "i18next/react-hooks", + "hooks": "useI18N", + "namespace": "io.gopluslabs.security", + "trans": "Translate", + "sourceMap": "inline" + } } ] } diff --git a/cspell.json b/cspell.json index f6e8e7121732..3b4b510323b6 100644 --- a/cspell.json +++ b/cspell.json @@ -308,6 +308,7 @@ "gamification", "getdodoroute", "getx", + "gopluslabs", "gorli", "gwapj", "hookform", @@ -350,6 +351,7 @@ "nyfi", "onflow", "openocean", + "pausable", "pkts", "pnpm", "poap", diff --git a/packages/icons/general/Risk.tsx b/packages/icons/general/Risk.tsx index ec4879d374e8..954ea2825e52 100644 --- a/packages/icons/general/Risk.tsx +++ b/packages/icons/general/Risk.tsx @@ -5,11 +5,11 @@ export const RiskIcon = createIcon( , '0 0 24 24', diff --git a/packages/mask/.webpack/config.ts b/packages/mask/.webpack/config.ts index e5a143627592..8fe5fbdd2ac9 100644 --- a/packages/mask/.webpack/config.ts +++ b/packages/mask/.webpack/config.ts @@ -88,6 +88,7 @@ export function createConfiguration(rawFlags: BuildFlags): Configuration { '@masknet/plugin-wallet': join(__dirname, '../../plugins/Wallet/src/'), '@masknet/plugin-file-service': join(__dirname, '../../plugins/FileService/src/'), '@masknet/plugin-cyberconnect': join(__dirname, '../../plugins/CyberConnect/src/'), + '@masknet/plugin-go-plus-security': join(__dirname, '../../plugins/GoPlusSecurity/src/'), '@masknet/external-plugin-previewer': join(__dirname, '../../external-plugin-previewer/src/'), '@masknet/public-api': join(__dirname, '../../public-api/src/'), '@masknet/sdk': join(__dirname, '../../mask-sdk/server/'), diff --git a/packages/mask/package.json b/packages/mask/package.json index 2e6c8b94087c..37acc43db1c3 100644 --- a/packages/mask/package.json +++ b/packages/mask/package.json @@ -29,6 +29,7 @@ "@masknet/plugin-rss3": "workspace:*", "@masknet/plugin-solana": "workspace:*", "@masknet/plugin-wallet": "workspace:*", + "@masknet/plugin-go-plus-security": "workspace:*", "@masknet/public-api": "workspace:*", "@masknet/sdk": "workspace:*", "@masknet/shared": "workspace:*", diff --git a/packages/mask/src/plugin-infra/register.js b/packages/mask/src/plugin-infra/register.js index 46f4973e183a..5cbbf531805e 100644 --- a/packages/mask/src/plugin-infra/register.js +++ b/packages/mask/src/plugin-infra/register.js @@ -10,6 +10,7 @@ import '@masknet/plugin-rss3' import '@masknet/plugin-dao' import '@masknet/plugin-solana' import '@masknet/plugin-cyberconnect' +import '@masknet/plugin-go-plus-security' import '../plugins/Wallet' import '../plugins/EVM' import '../plugins/RedPacket' diff --git a/packages/plugin-infra/src/types.ts b/packages/plugin-infra/src/types.ts index 9b2209b1bf7d..e0bc35cd42ec 100644 --- a/packages/plugin-infra/src/types.ts +++ b/packages/plugin-infra/src/types.ts @@ -688,6 +688,7 @@ export enum PluginId { UnlockProtocol = 'com.maskbook.unlockprotocol', FileService = 'com.maskbook.fileservice', CyberConnect = 'me.cyberconnect.app', + GoPlusSecurity = 'io.gopluslabs.security', // @masknet/scripts: insert-here } diff --git a/packages/plugins/GoPlusSecurity/package.json b/packages/plugins/GoPlusSecurity/package.json new file mode 100644 index 000000000000..378301090576 --- /dev/null +++ b/packages/plugins/GoPlusSecurity/package.json @@ -0,0 +1,20 @@ +{ + "name": "@masknet/plugin-go-plus-security", + "private": true, + "main": "./dist/index.js", + "types": "./dist/index.d.ts", + "dependencies": { + "react-feather": "^2.0.9", + "@masknet/icons": "workspace:*", + "@masknet/plugin-infra": "workspace:*", + "@masknet/shared": "workspace:*", + "@masknet/shared-base-ui": "workspace:*", + "@masknet/shared-base": "workspace:*", + "@masknet/theme": "workspace:*", + "@masknet/web3-providers": "workspace:*", + "@masknet/web3-shared-evm": "workspace:*", + "react-use": "^17.3.2", + "bignumber.js": "^9.0.2", + "urlcat": "^2.0.4" + } +} diff --git a/packages/plugins/GoPlusSecurity/src/Dashboard/index.tsx b/packages/plugins/GoPlusSecurity/src/Dashboard/index.tsx new file mode 100644 index 000000000000..c11379ee47db --- /dev/null +++ b/packages/plugins/GoPlusSecurity/src/Dashboard/index.tsx @@ -0,0 +1,9 @@ +import type { Plugin } from '@masknet/plugin-infra' +import { base } from '../base' + +const dashboard: Plugin.Dashboard.Definition = { + ...base, + init(signal) {}, +} + +export default dashboard diff --git a/packages/plugins/GoPlusSecurity/src/SNSAdaptor/CheckSecurityDialog.tsx b/packages/plugins/GoPlusSecurity/src/SNSAdaptor/CheckSecurityDialog.tsx new file mode 100644 index 000000000000..f679c307e226 --- /dev/null +++ b/packages/plugins/GoPlusSecurity/src/SNSAdaptor/CheckSecurityDialog.tsx @@ -0,0 +1,86 @@ +import { Box, DialogContent, Stack } from '@mui/material' +import { makeStyles, MaskDialog, useStylesExtends } from '@masknet/theme' +import { useI18N } from '../locales' +import { SearchBox } from './components/SearchBox' +import { useAsyncFn } from 'react-use' +import { GoPlusLabs } from '@masknet/web3-providers' +import { Searching } from './components/Searching' +import { SecurityPanel } from './components/SecurityPanel' +import { Footer } from './components/Footer' +import { Center, TokenSecurity } from './components/Common' +import { DefaultPlaceholder } from './components/DefaultPlaceholder' +import { NotFound } from './components/NotFound' +import type { ChainId } from '@masknet/web3-shared-evm' + +const useStyles = makeStyles()((theme) => ({ + root: { + width: 600, + }, + paperRoot: { + backgroundImage: 'none', + '&>h2': { + height: 30, + border: `1px solid ${theme.palette.divider}`, + padding: theme.spacing(1.875, 2.5, 1.875, 2.5), + marginBottom: 24, + }, + }, + content: { + width: 552, + height: 510, + maxHeight: 510, + paddingBottom: theme.spacing(3), + }, +})) + +export interface BuyTokenDialogProps extends withClasses { + open: boolean + onClose(): void +} + +export function CheckSecurityDialog(props: BuyTokenDialogProps) { + const t = useI18N() + const classes = useStylesExtends(useStyles(), props) + const { open, onClose } = props + + const [{ value, loading: searching, error }, onSearch] = useAsyncFn(async (chainId: ChainId, content: string) => { + const values = await GoPlusLabs.getTokenSecurity(chainId, [content.trim()]) + if (!Object.keys(values ?? {}).length) throw new Error('Contract Not Found') + return Object.entries(values ?? {}).map((x) => ({ ...x[1], contract: x[0], chainId }))[0] as + | TokenSecurity + | undefined + }, []) + + return ( + + + + + + + + {searching && ( +
+ +
+ )} + {error && !searching && } + {!error && !searching && value && } + {!error && !searching && !value && ( +
+ +
+ )} +
+ +
+ + + + + ) +} diff --git a/packages/plugins/GoPlusSecurity/src/SNSAdaptor/components/Common.tsx b/packages/plugins/GoPlusSecurity/src/SNSAdaptor/components/Common.tsx new file mode 100644 index 000000000000..df7c2abf0130 --- /dev/null +++ b/packages/plugins/GoPlusSecurity/src/SNSAdaptor/components/Common.tsx @@ -0,0 +1,52 @@ +import type { SecurityAPI } from '@masknet/web3-providers' +import { InfoIcon, RiskIcon, SuccessIcon } from '@masknet/icons' +import { memo, ReactNode } from 'react' +import { Stack } from '@mui/material' +import type { useI18N } from '../../locales' +import type { ChainId } from '@masknet/web3-shared-evm' + +export type TokenSecurity = SecurityAPI.ContractSecurity & + SecurityAPI.TokenSecurity & + SecurityAPI.TradingSecurity & { contract: string; chainId: ChainId } + +export enum SecurityMessageLevel { + High = 'High', + Medium = 'Medium', + Safe = 'Safe', +} + +export const Center = memo(({ children }) => ( + + {children} + +)) + +type DefineMapping = { + [key in SecurityMessageLevel]: { + i18nKey: keyof ReturnType + bgColor: string + titleColor: string + icon(size?: number): ReactNode + } +} + +export const DefineMapping: DefineMapping = { + [SecurityMessageLevel.High]: { + i18nKey: 'high_risk', + titleColor: '#FF5F5F', + bgColor: 'rgba(255, 95, 95, 0.1)', + icon: (size: number) => , + }, + [SecurityMessageLevel.Medium]: { + i18nKey: 'medium_risk', + titleColor: '#FFB915', + bgColor: 'rgba(255, 185, 21, 0.1)', + icon: (size: number) => , + }, + [SecurityMessageLevel.Safe]: { + i18nKey: 'low_risk', + titleColor: '#60DFAB', + bgColor: 'rgba(119, 224, 181, 0.1)', + icon: (size: number) => , + }, +} diff --git a/packages/plugins/GoPlusSecurity/src/SNSAdaptor/components/DefaultPlaceholder.tsx b/packages/plugins/GoPlusSecurity/src/SNSAdaptor/components/DefaultPlaceholder.tsx new file mode 100644 index 000000000000..f4604ced0978 --- /dev/null +++ b/packages/plugins/GoPlusSecurity/src/SNSAdaptor/components/DefaultPlaceholder.tsx @@ -0,0 +1,17 @@ +import { Box, Stack, Typography } from '@mui/material' +import { SecurityIcon } from '../icons/SecurityIcon' +import { useI18N } from '../../locales' + +export const DefaultPlaceholder = () => { + const t = useI18N() + return ( + + + + + + {t.default_placeholder()} + + + ) +} diff --git a/packages/plugins/GoPlusSecurity/src/SNSAdaptor/components/Footer.tsx b/packages/plugins/GoPlusSecurity/src/SNSAdaptor/components/Footer.tsx new file mode 100644 index 000000000000..06cee1054ae7 --- /dev/null +++ b/packages/plugins/GoPlusSecurity/src/SNSAdaptor/components/Footer.tsx @@ -0,0 +1,22 @@ +import { Box, Link, Stack, Typography } from '@mui/material' +import { useI18N } from '../../locales' +import { GoPlusLabLogo } from '../icons/Logo' +import { PLUGIN_OFFICIAL_WEBSITE } from '../../constants' + +export const Footer = () => { + const t = useI18N() + return ( + + + + + {t.powered_by_go_plus()} + + + + + + + + ) +} diff --git a/packages/plugins/GoPlusSecurity/src/SNSAdaptor/components/Loading.tsx b/packages/plugins/GoPlusSecurity/src/SNSAdaptor/components/Loading.tsx new file mode 100644 index 000000000000..29f8303eee8f --- /dev/null +++ b/packages/plugins/GoPlusSecurity/src/SNSAdaptor/components/Loading.tsx @@ -0,0 +1,22 @@ +import { makeStyles } from '@masknet/theme' +import type { SvgIconProps } from '@mui/material' +import { LoadingIcon } from '../icons/Loading' + +const useStyles = makeStyles()({ + animated: { + '@keyframes loadingAnimation': { + '0%': { + transform: 'rotate(0deg)', + }, + '100%': { + transform: 'rotate(360deg)', + }, + }, + animation: 'loadingAnimation 1s linear infinite', + }, +}) + +export const LoadingAnimation = (props: SvgIconProps) => { + const { classes } = useStyles() + return +} diff --git a/packages/plugins/GoPlusSecurity/src/SNSAdaptor/components/NotFound.tsx b/packages/plugins/GoPlusSecurity/src/SNSAdaptor/components/NotFound.tsx new file mode 100644 index 000000000000..89b95d44e949 --- /dev/null +++ b/packages/plugins/GoPlusSecurity/src/SNSAdaptor/components/NotFound.tsx @@ -0,0 +1,13 @@ +import { Stack, Typography } from '@mui/material' +import { useI18N } from '../../locales' + +export const NotFound = () => { + const t = useI18N() + return ( + + t.palette.error.main}> + {t.not_found_tip()} + + + ) +} diff --git a/packages/plugins/GoPlusSecurity/src/SNSAdaptor/components/RiskCard.tsx b/packages/plugins/GoPlusSecurity/src/SNSAdaptor/components/RiskCard.tsx new file mode 100644 index 000000000000..2992b7e11717 --- /dev/null +++ b/packages/plugins/GoPlusSecurity/src/SNSAdaptor/components/RiskCard.tsx @@ -0,0 +1,66 @@ +import { memo, ReactNode } from 'react' +import { DefineMapping, TokenSecurity } from './Common' +import { Box, Stack, Typography } from '@mui/material' +import type { SecurityMessage } from '../rules' +import { useI18N } from '../../locales' +import { makeStyles } from '@masknet/theme' + +const useStyles = makeStyles()((theme) => ({ + detectionCard: { + backgroundColor: theme.palette.background.default, + borderRadius: 8, + }, + icon: { + display: 'inline-flex', + lineHeight: '22px', + height: 22, + justifyContent: 'center', + alignItems: 'center', + }, + header: { + fontSize: 14, + lineHeight: '22px', + }, + description: { + fontSize: 12, + }, +})) + +interface RiskCardProps { + info: SecurityMessage + tokenSecurity: TokenSecurity +} + +export const RiskCard = memo(({ info, tokenSecurity }) => { + const t = useI18N() + return ( + + ) +}) + +interface RiskCardUIProps { + icon: ReactNode + title: string + titleColor: string + description?: string +} + +export const RiskCardUI = memo(({ icon, title, titleColor, description }) => { + const { classes } = useStyles() + return ( + + {icon} + + + {title} + + {description && {description}} + + + ) +}) diff --git a/packages/plugins/GoPlusSecurity/src/SNSAdaptor/components/SearchBox.tsx b/packages/plugins/GoPlusSecurity/src/SNSAdaptor/components/SearchBox.tsx new file mode 100644 index 000000000000..bdd180ef2958 --- /dev/null +++ b/packages/plugins/GoPlusSecurity/src/SNSAdaptor/components/SearchBox.tsx @@ -0,0 +1,125 @@ +import { Box, Button, InputAdornment, MenuItem, Stack, Typography } from '@mui/material' +import { useAsync } from 'react-use' +import { memo, useMemo, useState } from 'react' +import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown' +import { makeStyles, MaskColorVar, MaskTextField, ShadowRootMenu } from '@masknet/theme' +import { SearchIcon } from '@masknet/icons' +import { useI18N } from '../../locales' +import type { SecurityAPI } from '@masknet/web3-providers' +import { GoPlusLabs } from '@masknet/web3-providers' +import { ChainId, getChainDetailed } from '@masknet/web3-shared-evm' + +const useStyles = makeStyles()((theme) => ({ + root: { + width: '600px', + }, + content: { + width: '552px', + }, + selectedButton: { + width: '100%', + height: '100%', + fontWeight: 400, + borderColor: theme.palette.divider, + }, + searchButton: { + borderRadius: 8, + }, + menu: {}, + search: { + backgroundColor: 'transparent !important', + border: `solid 1px ${MaskColorVar.twitterBorderLine}`, + height: 48, + borderColor: theme.palette.divider, + borderRadius: 12, + }, +})) + +interface SearchBoxProps { + onSearch(chainId: ChainId, content: string): void +} + +const DEFAULT_SEARCH_CHAIN = ChainId.Mainnet + +function getChainName(chain?: SecurityAPI.SupportedChain) { + if (!chain) return getChainDetailed(ChainId.Mainnet)?.chain + if (chain.id === ChainId.BSC) return getChainDetailed(ChainId.BSC)?.shortName.toUpperCase() ?? chain.name + return getChainDetailed(chain.id)?.chain ?? chain.name +} + +export const SearchBox = memo(({ onSearch }) => { + const t = useI18N() + const { classes } = useStyles() + const [selectedChain, setSelectedChain] = useState() + const [searchContent, setSearchSearchContent] = useState() + const [anchorEl, setAnchorEl] = useState(null) + + const onClose = () => setAnchorEl(null) + const onOpen = (event: React.MouseEvent) => setAnchorEl(event.currentTarget) + + const { value: supportedChains = [] } = useAsync(GoPlusLabs.getSupportedChain, []) + + const menuElements = useMemo(() => { + if (!supportedChains.length) return + setSelectedChain(supportedChains[0]) + return ( + supportedChains.map((chain) => { + return ( + { + setSelectedChain(chain) + onClose() + }}> + {getChainName(chain)} + + ) + }) ?? [] + ) + }, [supportedChains.length]) + + return ( + + + + + + + { + if (e.key !== 'Enter') return + onSearch(selectedChain?.id ?? DEFAULT_SEARCH_CHAIN, searchContent ?? '') + }} + onChange={(e) => setSearchSearchContent(e.target.value)} + InputProps={{ + classes: { root: classes.search }, + startAdornment: ( + + + + ), + }} + /> + + + + + {menuElements} + + + ) +}) diff --git a/packages/plugins/GoPlusSecurity/src/SNSAdaptor/components/Searching.tsx b/packages/plugins/GoPlusSecurity/src/SNSAdaptor/components/Searching.tsx new file mode 100644 index 000000000000..20a7b1521f0d --- /dev/null +++ b/packages/plugins/GoPlusSecurity/src/SNSAdaptor/components/Searching.tsx @@ -0,0 +1,10 @@ +import { Stack } from '@mui/material' +import { LoadingAnimation } from './Loading' + +export const Searching = () => { + return ( + + + + ) +} diff --git a/packages/plugins/GoPlusSecurity/src/SNSAdaptor/components/SecurityPanel.tsx b/packages/plugins/GoPlusSecurity/src/SNSAdaptor/components/SecurityPanel.tsx new file mode 100644 index 000000000000..5ea7d29b7c1a --- /dev/null +++ b/packages/plugins/GoPlusSecurity/src/SNSAdaptor/components/SecurityPanel.tsx @@ -0,0 +1,148 @@ +import { Collapse, Link, Stack, Typography } from '@mui/material' +import { useI18N } from '../../locales' +import { ExternalLink } from 'react-feather' +import { makeStyles } from '@masknet/theme' +import { memo, useMemo, useState } from 'react' +import { DefineMapping, SecurityMessageLevel, TokenSecurity } from './Common' +import { SecurityMessages } from '../rules' +import { RiskCard, RiskCardUI } from './RiskCard' +import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown' +import { useTheme } from '@mui/system' +import { resolveGoLabLink } from '../../utils/helper' +import { TokenPanel } from './TokenPanel' + +interface TokenCardProps { + tokenSecurity: TokenSecurity +} + +const useStyles = makeStyles()((theme) => ({ + header: { + fontWeight: 500, + fontSize: 18, + }, + root: { + width: '600px', + }, + detectionCard: { + backgroundColor: theme.palette.background.default, + }, + detectionCollection: { + overflowY: 'auto', + '&::-webkit-scrollbar': { + display: 'none', + }, + }, +})) + +const LIST_HEIGHT = { + min: 154, + max: 308, +} + +export const SecurityPanel = memo(({ tokenSecurity }) => { + const { classes } = useStyles() + const t = useI18N() + const theme = useTheme() + + const [isCollapse, setCollapse] = useState(false) + + const makeMessageList = + tokenSecurity.is_whitelisted === '1' + ? [] + : SecurityMessages.filter( + (x) => + x.condition(tokenSecurity) && + x.level !== SecurityMessageLevel.Safe && + !x.shouldHide(tokenSecurity), + ).sort((a) => (a.level === SecurityMessageLevel.High ? -1 : 1)) + + const riskyFactors = makeMessageList.filter((x) => x.level === SecurityMessageLevel.High).length + const attentionFactors = makeMessageList.filter((x) => x.level === SecurityMessageLevel.Medium).length + + const securityMessageLevel = useMemo(() => { + if (riskyFactors) return SecurityMessageLevel.High + if (attentionFactors) return SecurityMessageLevel.Medium + return SecurityMessageLevel.Safe + }, [riskyFactors, attentionFactors]) + + return ( + + + + + + {t.token_info()} + + setCollapse(!isCollapse)} + sx={{ fontSize: 15, cursor: 'pointer' }} + /> + + + + {t.more_details()} + + + + + + + + + + + + + + {t.security_detection()} + + + {riskyFactors !== 0 && ( + + {DefineMapping[SecurityMessageLevel.High].icon(14)} + + {t.risky_factors({ quantity: riskyFactors.toString() })} + + + )} + {attentionFactors !== 0 && ( + + {DefineMapping[SecurityMessageLevel.Medium].icon(14)} + + {t.attention_factors({ quantity: attentionFactors.toString() })} + + + )} + + + + + {makeMessageList.map((x, i) => ( + + ))} + {(!makeMessageList.length || securityMessageLevel === SecurityMessageLevel.Safe) && ( + + )} + + + + + ) +}) diff --git a/packages/plugins/GoPlusSecurity/src/SNSAdaptor/components/TokenPanel.tsx b/packages/plugins/GoPlusSecurity/src/SNSAdaptor/components/TokenPanel.tsx new file mode 100644 index 000000000000..fc17746b810f --- /dev/null +++ b/packages/plugins/GoPlusSecurity/src/SNSAdaptor/components/TokenPanel.tsx @@ -0,0 +1,170 @@ +import { Link, Stack, Tooltip, Typography } from '@mui/material' +import { DefineMapping, SecurityMessageLevel, TokenSecurity } from './Common' +import parseInt from 'lodash-es/parseInt' +import { useI18N } from '../../locales' +import React from 'react' +import { useTheme } from '@mui/system' +import { ExternalLink } from 'react-feather' +import { makeStyles, usePortalShadowRoot } from '@masknet/theme' +import BigNumber from 'bignumber.js' +import { + ERC20Token, + formatEthereumAddress, + resolveAddressLinkOnExplorer, + resolveTokenLinkOnExplorer, +} from '@masknet/web3-shared-evm' + +const useStyles = makeStyles()((theme) => ({ + card: { + borderColor: theme.palette.divider, + borderStyle: 'solid', + borderWidth: 1, + padding: theme.spacing(1.5), + borderRadius: 9, + }, + subtitle: { + color: theme.palette.text.secondary, + fontWeight: 400, + fontSize: 14, + }, + cardValue: { + color: theme.palette.text.primary, + fontSize: 14, + }, + tooltip: { + color: theme.palette.text.buttonText, + fontSize: 12, + }, +})) + +const DEFAULT_PLACEHOLDER = '--' + +function formatTotalSupply(total?: number) { + if (!total) return DEFAULT_PLACEHOLDER + return new BigNumber(total).toFormat(3) +} + +interface TokenPanelProps { + tokenSecurity: TokenSecurity + securityMessageLevel: SecurityMessageLevel +} + +export const TokenPanel = React.forwardRef(({ tokenSecurity, securityMessageLevel }: TokenPanelProps, ref) => { + const t = useI18N() + const { classes } = useStyles() + const theme = useTheme() + + const totalSupply = usePortalShadowRoot((container) => { + return ( + theme.palette.text.buttonText} className={classes.tooltip}> + {tokenSecurity.total_supply} + + }> + {formatTotalSupply(tokenSecurity.total_supply)} + + ) + }) + + return ( + + + + {DefineMapping[securityMessageLevel].icon(33)} + + {t[DefineMapping[securityMessageLevel].i18nKey]({ quantity: '', rate: '' })} + + + + + {t.token_info_token_name()} + + {tokenSecurity.token_symbol}({tokenSecurity.token_name}) + + + + {t.token_info_token_contract_address()} + + + {tokenSecurity.contract + ? formatEthereumAddress(tokenSecurity.contract, 4) + : DEFAULT_PLACEHOLDER} + + + + + + + + {t.token_info_contract_creator()} + + + {tokenSecurity.creator_address + ? formatEthereumAddress(tokenSecurity.creator_address ?? '', 4) + : DEFAULT_PLACEHOLDER} + + {tokenSecurity.creator_address && ( + + + + )} + + + + {t.token_info_contract_owner()} + + + {tokenSecurity.owner_address + ? formatEthereumAddress(tokenSecurity.owner_address ?? '', 4) + : DEFAULT_PLACEHOLDER} + + {tokenSecurity.owner_address && ( + + + + )} + + + + {t.token_info_total_supply()} + {totalSupply} + + + + + ) +}) diff --git a/packages/plugins/GoPlusSecurity/src/SNSAdaptor/icons/Loading.tsx b/packages/plugins/GoPlusSecurity/src/SNSAdaptor/icons/Loading.tsx new file mode 100644 index 000000000000..f83c1449844d --- /dev/null +++ b/packages/plugins/GoPlusSecurity/src/SNSAdaptor/icons/Loading.tsx @@ -0,0 +1,21 @@ +import { createIcon } from '@masknet/icons' + +export const LoadingIcon = createIcon( + 'LoadingIcon', + <> + + + , + '0 0 20 20', +) diff --git a/packages/plugins/GoPlusSecurity/src/SNSAdaptor/icons/Logo.tsx b/packages/plugins/GoPlusSecurity/src/SNSAdaptor/icons/Logo.tsx new file mode 100644 index 000000000000..a7737f0e35bc --- /dev/null +++ b/packages/plugins/GoPlusSecurity/src/SNSAdaptor/icons/Logo.tsx @@ -0,0 +1,30 @@ +import { createIcon } from '@masknet/icons' + +export const GoPlusLabLogo = createIcon( + 'GoPlusLabLogo', + <> + + + + + + + + + + + + + , + '0 0 29 24', + [29, 24], +) diff --git a/packages/plugins/GoPlusSecurity/src/SNSAdaptor/icons/SecurityIcon.tsx b/packages/plugins/GoPlusSecurity/src/SNSAdaptor/icons/SecurityIcon.tsx new file mode 100644 index 000000000000..911793ca0e92 --- /dev/null +++ b/packages/plugins/GoPlusSecurity/src/SNSAdaptor/icons/SecurityIcon.tsx @@ -0,0 +1,53 @@ +import { createIcon } from '@masknet/icons' + +export const SecurityIcon = createIcon( + 'SecurityIcon', + + + + + + + + + + + + + + + + , + '0 0 48 48', +) diff --git a/packages/plugins/GoPlusSecurity/src/SNSAdaptor/index.tsx b/packages/plugins/GoPlusSecurity/src/SNSAdaptor/index.tsx new file mode 100644 index 000000000000..1273bd57d506 --- /dev/null +++ b/packages/plugins/GoPlusSecurity/src/SNSAdaptor/index.tsx @@ -0,0 +1,30 @@ +import type { Plugin } from '@masknet/plugin-infra' +import { base } from '../base' +import { CheckSecurityDialog } from './CheckSecurityDialog' +import { useState } from 'react' +import { ApplicationEntry } from '@masknet/shared' + +const sns: Plugin.SNSAdaptor.Definition = { + ...base, + init(signal) {}, + ApplicationEntries: [ + { + RenderEntryComponent() { + const [open, setOpen] = useState(false) + return ( + <> + setOpen(true)} + /> + {open && setOpen(false)} />} + + ) + }, + defaultSortingPriority: 12, + }, + ], +} + +export default sns diff --git a/packages/plugins/GoPlusSecurity/src/SNSAdaptor/rules.ts b/packages/plugins/GoPlusSecurity/src/SNSAdaptor/rules.ts new file mode 100644 index 000000000000..0f66eb822cc7 --- /dev/null +++ b/packages/plugins/GoPlusSecurity/src/SNSAdaptor/rules.ts @@ -0,0 +1,283 @@ +import { SecurityMessageLevel, TokenSecurity } from './components/Common' +import type { useI18N } from '../locales' +import parseInt from 'lodash-es/parseInt' + +export type I18nOptions = 'rate' | 'quantity' + +export interface SecurityMessage { + type: 'contract-security' | 'transaction-security' + level: SecurityMessageLevel + condition(info: TokenSecurity): boolean + titleKey: keyof ReturnType + messageKey: keyof ReturnType + i18nParams?: (info: TokenSecurity) => { [key in I18nOptions]: string } + shouldHide(info: TokenSecurity): boolean +} + +const percentageToNumber = (value?: string) => parseInt((value ?? '').replace('%', '')) * 100 + +export const SecurityMessages: SecurityMessage[] = [ + // open source + { + type: 'contract-security', + level: SecurityMessageLevel.Safe, + condition: (info: TokenSecurity) => info.is_open_source === '1', + titleKey: 'risk_contract_source_code_verified_title', + messageKey: 'risk_contract_source_code_verified_body', + shouldHide: (info: TokenSecurity) => info.is_open_source === undefined, + }, + { + type: 'contract-security', + level: SecurityMessageLevel.High, + condition: (info: TokenSecurity) => info.is_open_source === '0', + titleKey: 'risk_contract_source_code_not_verified_title', + messageKey: 'risk_contract_source_code_not_verified_body', + shouldHide: (info: TokenSecurity) => info.is_open_source === undefined, + }, + // proxy + { + type: 'contract-security', + level: SecurityMessageLevel.Medium, + condition: (info: TokenSecurity) => info.is_proxy === '1', + titleKey: 'risk_proxy_contract_title', + messageKey: 'risk_proxy_contract_body', + shouldHide: (info: TokenSecurity) => info.is_proxy === undefined, + }, + { + type: 'contract-security', + level: SecurityMessageLevel.Safe, + condition: (info: TokenSecurity) => info.is_proxy === '0', + titleKey: 'risk_no_proxy_title', + messageKey: 'risk_no_proxy_body', + shouldHide: (info: TokenSecurity) => info.is_proxy === undefined, + }, + // mint + { + type: 'contract-security', + level: SecurityMessageLevel.Safe, + condition: (info: TokenSecurity) => info.is_mintable === '0', + titleKey: 'risk_no_mint_function_title', + messageKey: 'risk_no_mint_function_body', + shouldHide: (info: TokenSecurity) => info.is_mintable === undefined, + }, + { + type: 'contract-security', + level: SecurityMessageLevel.Medium, + condition: (info: TokenSecurity) => info.is_mintable === '1', + titleKey: 'risk_mint_function_title', + messageKey: 'risk_mint_function_body', + shouldHide: (info: TokenSecurity) => info.is_mintable === undefined, + }, + // owner change balance + { + type: 'contract-security', + level: SecurityMessageLevel.Safe, + condition: (info: TokenSecurity) => info.owner_change_balance === '0', + titleKey: 'risk_owner_can_not_change_balance_title', + messageKey: 'risk_owner_can_not_change_balance_body', + shouldHide: (info: TokenSecurity) => info.owner_change_balance === undefined, + }, + { + type: 'contract-security', + level: SecurityMessageLevel.Medium, + condition: (info: TokenSecurity) => info.owner_change_balance === '1', + titleKey: 'risk_owner_change_balance_title', + messageKey: 'risk_owner_change_balance_body', + shouldHide: (info: TokenSecurity) => info.owner_change_balance === undefined, + }, + // can take back ownership + { + type: 'contract-security', + level: SecurityMessageLevel.Safe, + condition: (info: TokenSecurity) => info.can_take_back_ownership === '0', + titleKey: 'risk_no_can_take_back_ownership_title', + messageKey: 'risk_no_can_take_back_ownership_body', + shouldHide: (info: TokenSecurity) => info.can_take_back_ownership === undefined, + }, + { + type: 'contract-security', + level: SecurityMessageLevel.Medium, + condition: (info: TokenSecurity) => info.can_take_back_ownership === '1', + titleKey: 'risk_can_take_back_ownership_title', + messageKey: 'risk_can_take_back_ownership_body', + shouldHide: (info: TokenSecurity) => info.can_take_back_ownership === undefined, + }, + // buy tax + { + type: 'transaction-security', + level: SecurityMessageLevel.Safe, + condition: (info: TokenSecurity) => percentageToNumber(info.buy_tax) < 10, + titleKey: 'risk_buy_tax_title', + messageKey: 'risk_buy_tax_body', + i18nParams: (info: TokenSecurity) => ({ + rate: `${percentageToNumber(info.buy_tax)}%`, + quantity: '', + }), + shouldHide: (info: TokenSecurity) => info.buy_tax === undefined, + }, + { + type: 'contract-security', + level: SecurityMessageLevel.Medium, + condition: (info: TokenSecurity) => + percentageToNumber(info.buy_tax) >= 10 && percentageToNumber(info.buy_tax) < 50, + titleKey: 'risk_buy_tax_title', + messageKey: 'risk_buy_tax_body', + i18nParams: (info: TokenSecurity) => ({ + rate: `${percentageToNumber(info.buy_tax)}%`, + quantity: '', + }), + shouldHide: (info: TokenSecurity) => info.buy_tax === undefined, + }, + { + type: 'contract-security', + level: SecurityMessageLevel.High, + condition: (info: TokenSecurity) => percentageToNumber(info.buy_tax) >= 50, + titleKey: 'risk_buy_tax_title', + messageKey: 'risk_buy_tax_body', + i18nParams: (info: TokenSecurity) => ({ + rate: `${percentageToNumber(info.buy_tax)}%`, + quantity: '', + }), + shouldHide: (info: TokenSecurity) => info.buy_tax === undefined, + }, + // sell tax + { + type: 'transaction-security', + level: SecurityMessageLevel.Safe, + condition: (info: TokenSecurity) => percentageToNumber(info.sell_tax) < 10, + titleKey: 'risk_sell_tax_title', + messageKey: 'risk_sell_tax_body', + i18nParams: (info: TokenSecurity) => ({ + rate: `${percentageToNumber(info.sell_tax)}%`, + quantity: '', + }), + shouldHide: (info: TokenSecurity) => info.sell_tax === undefined, + }, + { + type: 'contract-security', + level: SecurityMessageLevel.Medium, + condition: (info: TokenSecurity) => + percentageToNumber(info.sell_tax) >= 10 && percentageToNumber(info.sell_tax) < 50, + titleKey: 'risk_sell_tax_title', + messageKey: 'risk_sell_tax_body', + i18nParams: (info: TokenSecurity) => ({ + rate: `${percentageToNumber(info.sell_tax)}%`, + quantity: '', + }), + shouldHide: (info: TokenSecurity) => info.sell_tax === undefined, + }, + { + type: 'contract-security', + level: SecurityMessageLevel.High, + condition: (info: TokenSecurity) => percentageToNumber(info.sell_tax) >= 50, + titleKey: 'risk_sell_tax_title', + messageKey: 'risk_sell_tax_body', + i18nParams: (info: TokenSecurity) => ({ + rate: `${percentageToNumber(info.sell_tax)}%`, + quantity: '', + }), + shouldHide: (info: TokenSecurity) => info.sell_tax === undefined, + }, + // honeypot + { + type: 'transaction-security', + level: SecurityMessageLevel.Safe, + condition: (info: TokenSecurity) => info.is_honeypot === '0', + titleKey: 'risk_is_not_honeypot_title', + messageKey: 'risk_is_not_honeypot_body', + shouldHide: (info: TokenSecurity) => info.is_honeypot === undefined, + }, + { + type: 'contract-security', + level: SecurityMessageLevel.High, + condition: (info: TokenSecurity) => info.is_honeypot === '1', + titleKey: 'risk_is_honeypot_title', + messageKey: 'risk_is_honeypot_body', + shouldHide: (info: TokenSecurity) => info.is_honeypot === undefined, + }, + // transfer_pausable + { + type: 'transaction-security', + level: SecurityMessageLevel.Safe, + condition: (info: TokenSecurity) => info.transfer_pausable === '0', + titleKey: 'risk_no_code_transfer_pausable_title', + messageKey: 'risk_no_code_transfer_pausable_title', + shouldHide: (info: TokenSecurity) => info.transfer_pausable === undefined, + }, + { + type: 'contract-security', + level: SecurityMessageLevel.Medium, + condition: (info: TokenSecurity) => info.transfer_pausable === '1', + titleKey: 'risk_transfer_pausable_title', + messageKey: 'risk_transfer_pausable_body', + shouldHide: (info: TokenSecurity) => info.transfer_pausable === undefined, + }, + // anti whale + { + type: 'transaction-security', + level: SecurityMessageLevel.Safe, + condition: (info: TokenSecurity) => info.is_anti_whale === '0', + titleKey: 'risk_is_no_anti_whale_title', + messageKey: 'risk_is_no_anti_whale_body', + shouldHide: (info: TokenSecurity) => info.is_anti_whale === undefined, + }, + { + type: 'contract-security', + level: SecurityMessageLevel.Medium, + condition: (info: TokenSecurity) => info.is_anti_whale === '1', + titleKey: 'risk_is_anti_whale_title', + messageKey: 'risk_is_anti_whale_body', + shouldHide: (info: TokenSecurity) => info.is_anti_whale === undefined, + }, + // slippage modifiable + { + type: 'transaction-security', + level: SecurityMessageLevel.Safe, + condition: (info: TokenSecurity) => info.slippage_modifiable === '0', + titleKey: 'risk_not_slippage_modifiable_title', + messageKey: 'risk_not_slippage_modifiable_body', + shouldHide: (info: TokenSecurity) => info.slippage_modifiable === undefined, + }, + { + type: 'contract-security', + level: SecurityMessageLevel.Medium, + condition: (info: TokenSecurity) => info.slippage_modifiable === '1', + titleKey: 'risk_slippage_modifiable_title', + messageKey: 'risk_slippage_modifiable_body', + shouldHide: (info: TokenSecurity) => info.slippage_modifiable === undefined, + }, + // black list + { + type: 'transaction-security', + level: SecurityMessageLevel.Safe, + condition: (info: TokenSecurity) => info.is_blacklisted === '0', + titleKey: 'risk_not_is_blacklisted_title', + messageKey: 'risk_not_is_blacklisted_body', + shouldHide: (info: TokenSecurity) => info.is_blacklisted === undefined, + }, + { + type: 'contract-security', + level: SecurityMessageLevel.Medium, + condition: (info: TokenSecurity) => info.is_blacklisted === '1', + titleKey: 'risk_is_blacklisted_title', + messageKey: 'risk_is_blacklisted_body', + shouldHide: (info: TokenSecurity) => info.is_blacklisted === undefined, + }, + // white list + { + type: 'transaction-security', + level: SecurityMessageLevel.Safe, + condition: (info: TokenSecurity) => info.is_whitelisted === '0', + titleKey: 'risk_not_is_whitelisted_title', + messageKey: 'risk_not_is_whitelisted_body', + shouldHide: (info: TokenSecurity) => info.is_whitelisted === undefined, + }, + { + type: 'contract-security', + level: SecurityMessageLevel.Medium, + condition: (info: TokenSecurity) => info.is_whitelisted === '1', + titleKey: 'risk_is_whitelisted_title', + messageKey: 'risk_is_whitelisted_body', + shouldHide: (info: TokenSecurity) => info.is_whitelisted === undefined, + }, +] diff --git a/packages/plugins/GoPlusSecurity/src/Worker/index.ts b/packages/plugins/GoPlusSecurity/src/Worker/index.ts new file mode 100644 index 000000000000..6c436f1cb4fb --- /dev/null +++ b/packages/plugins/GoPlusSecurity/src/Worker/index.ts @@ -0,0 +1,9 @@ +import type { Plugin } from '@masknet/plugin-infra' +import { base } from '../base' + +const worker: Plugin.Worker.Definition = { + ...base, + init(signal, context) {}, +} + +export default worker diff --git a/packages/plugins/GoPlusSecurity/src/assets/security-icon.png b/packages/plugins/GoPlusSecurity/src/assets/security-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..2a0d93498a54677ddd02b2109b39fbd98169133c GIT binary patch literal 1721 zcmV;q21fabP)Dk#%pSSH<&v{!;$@wS$jJ18w zInQs;^Stl*DAT67a^=dED_5>uwPAZ*2i_xC3HRdVh8X4td+^K?3ycD5jH0MIise;d z>@z}1XKxt8fiU`N+Oc_gC+aycf?ONJ48E^|5M>Gd#jBzyt`r$j8Nn%E2%{WAHugm@ z5NN|;4vb22O*a;--jC;KpN@n^KvsyqXrLW$R)(=f1rReQfQbyNYC|}wB*#tAsFzXZ zHgsTCUcq@HnB$G0)EmNDQ3^3}z(YKM$6+d6JAx}H@^uYR^SAPNyLLRFmhU){WZk}} z!Ra5A$EvX70bRPvktFNN4GmD&8F{Pru7k=2$>x<&{a4U9__1+q7cG z0?JfgQxVN>O<&8~&DM?tWL92g(r33P7LeWY($_{RdXXam9f|X>rzSe>(BZWFAaB=- z9SLat!OUmx>GbFLx+tb_RqaSX>71!?>z6!ETmh=v<*`<+6cF7L<2z94(FYuhCLIo) zu&U@gMo+*|0ffO0_IRvh3vQenE>%0)Alel4hBzdXjS zeG!~80$S07**xB?RUSf+??{FDRYl`;-h5R4yb1@}5i$Z&@<4;X1@rihRM^;mXgVLf zX?;3hzUvXTefAp;Z8(PhwVjBs2_=5g?@gayo&21kL9dBn5s%ffDzt|dqyw{Rn)Z#- zuR&)EXWfo}aBTe{;H_$)#FN%z-XMB6olLqfPY+@7I4x_*m)OV;&W?>MYkkH#_>26x zOg^;nm?;>^W&YtGHy!vW0jLABc$}6+)4j?EqV)cA^X}w~mCah`yeJ_l_$)kH`*D=V zXj@_i_<|p(Rnw~a-oMtS^Zs?6Qos}TE)&yVBe0=K`^n!o`nB>PkI|Os5jz!GM7MqP z8SBW!?BFE&4G)w|KrURItXo}oMT(vf^<2M79#c|2f@06}JWg9unMK)}8gj~>)7`_d z2r##RTZZ$PYu7c1d~Av5IFHem0x>*IPigUk&xg+kLp-?Da7gjvnjhYqe2uaxRoRt# z7VA z^H#R4@(~`NZPo6=^t!!RmM=)OB9;JAHdqmX<=ZOt%;7QG7D1}-f+rt6sqaHJd(m`m zRW#elfEM!jl&NMfUdc72f(Ard*@+i?Vf699R5@jd(X3=eKb@AhRk~yzk4d@cizMDC zqC7YiR@$U@?3A{}W67E5YfphTY*F33>2ij&NTh{dwn{zCt6eObi6E_vqF8lbx>olo z4=nvcF`ZJarr)Tj4Z%aVXfa&fPP*(GqY8+BTdp`#!s;*qQa^=dED<|uJr9##~RSXjE P00000NkvXXu0mjfBb!gc literal 0 HcmV?d00001 diff --git a/packages/plugins/GoPlusSecurity/src/base.ts b/packages/plugins/GoPlusSecurity/src/base.ts new file mode 100644 index 000000000000..c19fe3023fe1 --- /dev/null +++ b/packages/plugins/GoPlusSecurity/src/base.ts @@ -0,0 +1,17 @@ +import type { Plugin } from '@masknet/plugin-infra' +import { PLUGIN_DESCRIPTION, PLUGIN_ID, PLUGIN_NAME } from './constants' +import { languages } from './locales/languages' + +export const base: Plugin.Shared.Definition = { + ID: PLUGIN_ID, + icon: '', + name: { fallback: PLUGIN_NAME }, + description: { fallback: PLUGIN_DESCRIPTION }, + publisher: { name: { fallback: 'Mask Network' }, link: 'https://mask.io/' }, + enableRequirement: { + architecture: { app: false, web: true }, + networks: { type: 'opt-out', networks: {} }, + target: 'stable', + }, + i18n: languages, +} diff --git a/packages/plugins/GoPlusSecurity/src/constants.ts b/packages/plugins/GoPlusSecurity/src/constants.ts new file mode 100644 index 000000000000..313d7a66f428 --- /dev/null +++ b/packages/plugins/GoPlusSecurity/src/constants.ts @@ -0,0 +1,7 @@ +import { PluginId } from '@masknet/plugin-infra' + +export const PLUGIN_ID = PluginId.GoPlusSecurity +export const PLUGIN_META_KEY = `${PluginId.GoPlusSecurity}:1` +export const PLUGIN_DESCRIPTION = 'Go+ Security Engine' +export const PLUGIN_NAME = 'GoPlusSecurity' +export const PLUGIN_OFFICIAL_WEBSITE = 'https://gopluslabs.io' diff --git a/packages/plugins/GoPlusSecurity/src/env.d.ts b/packages/plugins/GoPlusSecurity/src/env.d.ts new file mode 100644 index 000000000000..868322d5ff30 --- /dev/null +++ b/packages/plugins/GoPlusSecurity/src/env.d.ts @@ -0,0 +1 @@ +/// diff --git a/packages/plugins/GoPlusSecurity/src/index.ts b/packages/plugins/GoPlusSecurity/src/index.ts new file mode 100644 index 000000000000..ec9b1a34e7af --- /dev/null +++ b/packages/plugins/GoPlusSecurity/src/index.ts @@ -0,0 +1,23 @@ +import { registerPlugin } from '@masknet/plugin-infra' +import { base } from './base' + +export * from './constants' + +registerPlugin({ + ...base, + SNSAdaptor: { + load: () => import('./SNSAdaptor'), + hotModuleReload: (hot) => + import.meta.webpackHot && import.meta.webpackHot.accept('./SNSAdaptor', () => hot(import('./SNSAdaptor'))), + }, + Dashboard: { + load: () => import('./Dashboard'), + hotModuleReload: (hot) => + import.meta.webpackHot && import.meta.webpackHot.accept('./Dashboard', () => hot(import('./Dashboard'))), + }, + Worker: { + load: () => import('./Worker'), + hotModuleReload: (hot) => + import.meta.webpackHot && import.meta.webpackHot.accept('./Worker', () => hot(import('./Worker'))), + }, +}) diff --git a/packages/plugins/GoPlusSecurity/src/locales/en-US.json b/packages/plugins/GoPlusSecurity/src/locales/en-US.json new file mode 100644 index 000000000000..9f208758c4c5 --- /dev/null +++ b/packages/plugins/GoPlusSecurity/src/locales/en-US.json @@ -0,0 +1,74 @@ +{ + "dialog_title": "Check Security", + "powered_by_go_plus": "Powered by Go+", + "high_risk": "High Risk", + "low_risk": "Low Risk", + "medium_risk": "Medium Risk", + "search": "Search", + "search_input_placeholder": "Please enter token contract address.", + "token_info": "Token info", + "more_details": "More Details", + "security_detection": "Security Detection", + "risky_factors": "{{quantity}} Risky factors", + "attention_factors": "{{quantity}} Attention factors", + "security_info_code_not_verify_title": "Contract source code not verified", + "security_info_code_not_verify_message": "This token contract has not been verified. We cannot check the contract code for details. Unsourced token contracts are likely to have malicious functions to defraud users of their assets", + "security_info_functions_that_can_suspend_trading_title": "Functions that can suspend trading", + "security_info_functions_that_can_suspend_trading_message": "If a suspendable code is included, the token maybe neither be bought nor sold (honeypot risk). ", + "token_info_token_name": "Token Name", + "token_info_token_contract_address": "Token Contract Address", + "token_info_contract_creator": "Contract Creator", + "token_info_contract_owner": "Contract Owner", + "token_info_total_supply": "Total Supply", + "default_placeholder": "Note: Scams detections might not be 100% guaranteed.", + "not_found_tip": "Network error or the on-chain data is abnormal. Please switch to the correct network or check the address again.", + "risk_safe_description": "This token has no risky or attention factors.", + "risk_contract_source_code_verified_title": "Contract source code verified", + "risk_contract_source_code_verified_body": "This token contract is open source. You can check the contract code for details. Unsourced token contracts are likely to have malicious functions to defraud their users of their assets.", + "risk_contract_source_code_not_verified_title": "Contract source code not verified", + "risk_contract_source_code_not_verified_body": "This token contract has not been verified. We cannot check the contract code for details. Unsourced token contracts are likely to have malicious functions to defraud users of their assets.", + "risk_proxy_contract_title": "Proxy contract", + "risk_proxy_contract_body": "This contract is an Admin Upgradeability Proxy. The proxy contract means the contract owner can modifiy the function of the token and could possibly effect the price.There is possibly a way for the team to Rug or Scam. Please confirm the details with the project team before buying.", + "risk_no_proxy_title": "No proxy", + "risk_no_proxy_body": "There is no proxy in the contract. The proxy contract means contract owner can modifiy the function of the token and possibly effect the price.", + "risk_mint_function_title": "Mint function", + "risk_mint_function_body": "The contract may contain additional issuance functions, which could maybe generate a large number of tokens, resulting in significant fluctuations in token prices. It is recommended to confirm with the project team whether it complies with the token issuance instructions.", + "risk_no_mint_function_title": "No mint function", + "risk_no_mint_function_body": "Mint function is transparent or non-existent. Hidden mint functions may increase the amount of tokens in circulation and effect the price of the token.", + "risk_can_take_back_ownership_title": "Functions with retrievable ownership", + "risk_can_take_back_ownership_body": "If this function exists, it is possible for the project owner to regain ownership even after relinquishing it", + "risk_no_can_take_back_ownership_title": "No function found that retrieves ownership", + "risk_no_can_take_back_ownership_body": "If this function exists, it is possible for the project owner to regain ownership even after relinquishing it", + "risk_owner_change_balance_title": "Owner can change balance", + "risk_owner_change_balance_body": "The contract owner has the authority to modify the balance of tokens at other addresses, which may result in a loss of assets.", + "risk_owner_can_not_change_balance_title": "Owner can't change balance", + "risk_owner_can_not_change_balance_body": "The contract owner is not found to have the authority to modify the balance of tokens at other addresses.", + "risk_buy_tax_title": "Buy Tax: {{rate}}", + "risk_buy_tax_body": "Above 10% may be considered a high tax rate. More than 50% tax rate means may not be tradable.", + "risk_sell_tax_title": "Sell Tax: {{rate}}", + "risk_sell_tax_body": "Above 10% may be considered a high tax rate. More than 50% tax rate means may not be tradable.", + "risk_is_honeypot_title": "May the token is a honeypot.", + "risk_is_honeypot_body": "This token contract has a code that states that it cannot be sold. Maybe this is a honeypot.", + "risk_is_not_honeypot_title": "This does not appear to be a honeypot.", + "risk_is_not_honeypot_body": "We are not aware of any code that prevents the sale of tokens.", + "risk_transfer_pausable_title": "Functions that can suspend trading", + "risk_transfer_pausable_body": "If a suspendable code is included, the token maybe neither be bought nor sold (honeypot risk).", + "risk_no_code_transfer_pausable_title": "No codes found to suspend trading.", + "risk_no_code_transfer_pausable_body": "If a suspendable code is included, the token maybe neither be bought nor sold (honeypot risk).", + "risk_is_anti_whale_title": " Anti_whale(Limited number of transactions)", + "risk_is_anti_whale_body": "The number of token transactions is limited. The number of scam token transactions may be limited (honeypot risk).", + "risk_is_no_anti_whale_title": "No anti_whale(Unlimited number of transactions)", + "risk_is_no_anti_whale_body": "There is no limit to the number of token transactions. The number of scam token transactions may be limited (honeypot risk).", + "risk_slippage_modifiable_title": "Tax can be modified", + "risk_slippage_modifiable_body": " The contract owner may contain the authority to modify the transaction tax. If the transaction tax is increased to more than 49%, the tokens will not be able to be traded (honeypot risk).", + "risk_not_slippage_modifiable_title": "Tax cannot be modified", + "risk_not_slippage_modifiable_body": "The contract owner may not contain the authority to modify the transaction tax. If the transaction tax is increased to more than 49%, the tokens will not be able to be traded (honeypot risk).", + "risk_is_blacklisted_title": "Blacklist function", + "risk_is_blacklisted_body": "The blacklist function is included. Some addresses may not be able to trade normally (honeypot risk).", + "risk_not_is_blacklisted_title": "No blacklist", + "risk_not_is_blacklisted_body": "The blacklist function is not included. If there is a blacklist, some addresses may not be able to trade normally (honeypot risk).", + "risk_is_whitelisted_title": "Whitelist function", + "risk_is_whitelisted_body": "The whitelist function is included. Some addresses may not be able to trade normally (honeypot risk).", + "risk_not_is_whitelisted_title": "No whitelist", + "risk_not_is_whitelisted_body": "The whitelist function is not included. If there is a whitelist, some addresses may not be able to trade normally (honeypot risk)." +} diff --git a/packages/plugins/GoPlusSecurity/src/locales/index.ts b/packages/plugins/GoPlusSecurity/src/locales/index.ts new file mode 100644 index 000000000000..d6ead60252e4 --- /dev/null +++ b/packages/plugins/GoPlusSecurity/src/locales/index.ts @@ -0,0 +1,6 @@ +// 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 + +export * from './i18n_generated' diff --git a/packages/plugins/GoPlusSecurity/src/locales/ja-JP.json b/packages/plugins/GoPlusSecurity/src/locales/ja-JP.json new file mode 100644 index 000000000000..0967ef424bce --- /dev/null +++ b/packages/plugins/GoPlusSecurity/src/locales/ja-JP.json @@ -0,0 +1 @@ +{} diff --git a/packages/plugins/GoPlusSecurity/src/locales/ko-KR.json b/packages/plugins/GoPlusSecurity/src/locales/ko-KR.json new file mode 100644 index 000000000000..0967ef424bce --- /dev/null +++ b/packages/plugins/GoPlusSecurity/src/locales/ko-KR.json @@ -0,0 +1 @@ +{} diff --git a/packages/plugins/GoPlusSecurity/src/locales/languages.ts b/packages/plugins/GoPlusSecurity/src/locales/languages.ts new file mode 100644 index 000000000000..8d0cd55c479a --- /dev/null +++ b/packages/plugins/GoPlusSecurity/src/locales/languages.ts @@ -0,0 +1,34 @@ +// 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 ja_JP from './ja-JP.json' +import ko_KR from './ko-KR.json' +import qya_AA from './qya-AA.json' +import zh_CN from './zh-CN.json' +import zh_TW from './zh-TW.json' +export const languages = { + en: en_US, + ja: ja_JP, + ko: ko_KR, + qy: qya_AA, + 'zh-CN': zh_CN, + zh: zh_TW, +} +// @ts-ignore +if (import.meta.webpackHot) { + // @ts-ignore + import.meta.webpackHot.accept( + ['./en-US.json', './ja-JP.json', './ko-KR.json', './qya-AA.json', './zh-CN.json', './zh-TW.json'], + () => + globalThis.dispatchEvent?.( + new CustomEvent('MASK_I18N_HMR', { + detail: [ + 'io.mask.debugger', + { en: en_US, ja: ja_JP, ko: ko_KR, qy: qya_AA, 'zh-CN': zh_CN, zh: zh_TW }, + ], + }), + ), + ) +} diff --git a/packages/plugins/GoPlusSecurity/src/locales/qya-AA.json b/packages/plugins/GoPlusSecurity/src/locales/qya-AA.json new file mode 100644 index 000000000000..0967ef424bce --- /dev/null +++ b/packages/plugins/GoPlusSecurity/src/locales/qya-AA.json @@ -0,0 +1 @@ +{} diff --git a/packages/plugins/GoPlusSecurity/src/locales/zh-CN.json b/packages/plugins/GoPlusSecurity/src/locales/zh-CN.json new file mode 100644 index 000000000000..0967ef424bce --- /dev/null +++ b/packages/plugins/GoPlusSecurity/src/locales/zh-CN.json @@ -0,0 +1 @@ +{} diff --git a/packages/plugins/GoPlusSecurity/src/locales/zh-TW.json b/packages/plugins/GoPlusSecurity/src/locales/zh-TW.json new file mode 100644 index 000000000000..0967ef424bce --- /dev/null +++ b/packages/plugins/GoPlusSecurity/src/locales/zh-TW.json @@ -0,0 +1 @@ +{} diff --git a/packages/plugins/GoPlusSecurity/src/messages.ts b/packages/plugins/GoPlusSecurity/src/messages.ts new file mode 100644 index 000000000000..0c4bc0b6e72a --- /dev/null +++ b/packages/plugins/GoPlusSecurity/src/messages.ts @@ -0,0 +1,13 @@ +import { createPluginMessage, PluginMessageEmitter } from '@masknet/plugin-infra' +import { PLUGIN_ID } from './constants' + +type CheckSecurityDialogEvent = { open: boolean } + +interface PluginGoPlusSecurityMessage { + checkSecurityDialogEvent: CheckSecurityDialogEvent + rpc: unknown +} + +if (import.meta.webpackHot) import.meta.webpackHot.accept() +export const PluginGoPlusSecurityMessages: PluginMessageEmitter = + createPluginMessage(PLUGIN_ID) diff --git a/packages/plugins/GoPlusSecurity/src/utils/helper.ts b/packages/plugins/GoPlusSecurity/src/utils/helper.ts new file mode 100644 index 000000000000..a1d47642fe4a --- /dev/null +++ b/packages/plugins/GoPlusSecurity/src/utils/helper.ts @@ -0,0 +1,5 @@ +import urlcat from 'urlcat' + +export function resolveGoLabLink(chainId: string, address: string) { + return urlcat('https://gopluslabs.io/token-security/:chainId/:address', { chainId, address }) +} diff --git a/packages/plugins/GoPlusSecurity/tsconfig.json b/packages/plugins/GoPlusSecurity/tsconfig.json new file mode 100644 index 000000000000..7503903514d1 --- /dev/null +++ b/packages/plugins/GoPlusSecurity/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "../tsconfig.json", + "compilerOptions": { + "rootDir": "src", + "outDir": "dist", + "tsBuildInfoFile": "dist/.tsbuildinfo" + }, + "include": ["src", "src/**/*.json"], + "references": [{ "path": "../../plugin-infra" }, { "path": "../../shared" }, { "path": "../../web3-providers" }] +} diff --git a/packages/shared-base/src/utils/requestComposition.ts b/packages/shared-base/src/utils/requestComposition.ts new file mode 100644 index 000000000000..4fa125750129 --- /dev/null +++ b/packages/shared-base/src/utils/requestComposition.ts @@ -0,0 +1,10 @@ +import { CrossIsolationMessages } from '@masknet/shared-base' +export function requestComposition(startupPlugin: string) { + CrossIsolationMessages.events.requestComposition.sendToLocal({ + reason: 'timeline', + open: true, + options: { + startupPlugin, + }, + }) +} diff --git a/packages/shared/src/hooks/useMenu.tsx b/packages/shared/src/hooks/useMenu.tsx index d23fe86f93be..93ae72f84a24 100644 --- a/packages/shared/src/hooks/useMenu.tsx +++ b/packages/shared/src/hooks/useMenu.tsx @@ -4,6 +4,7 @@ import { useUpdate } from 'react-use' /** Provide ShadowRootMenu for useMenu in content script. */ export const useMenuContext = createContext>(Menu) + /** * A util hooks for easier to use ``s. * @@ -15,6 +16,7 @@ export function useMenu(...elements: Array) { } export interface useMenuConfig extends Partial {} + export function useMenuConfig( elements: Array, config: useMenuConfig, diff --git a/packages/web3-providers/src/gopluslabs/constants.ts b/packages/web3-providers/src/gopluslabs/constants.ts index 79eb1f0198ed..3d052ffb1f90 100644 --- a/packages/web3-providers/src/gopluslabs/constants.ts +++ b/packages/web3-providers/src/gopluslabs/constants.ts @@ -1 +1 @@ -export const GO_PLUS_LABS_ROOT_URL = 'https://api.gopluslabs.io' +export const GO_PLUS_LABS_ROOT_URL = 'https://gopluslabs.r2d2.to' diff --git a/packages/web3-providers/src/gopluslabs/index.ts b/packages/web3-providers/src/gopluslabs/index.ts index a8f1c605b9d4..ba681d537f16 100644 --- a/packages/web3-providers/src/gopluslabs/index.ts +++ b/packages/web3-providers/src/gopluslabs/index.ts @@ -1,15 +1,24 @@ -import { uniqBy } from 'lodash-unified' +import { ChainId } from '@masknet/web3-shared-evm' +import { parseInt, uniqBy } from 'lodash-unified' import urlcat from 'urlcat' import type { SecurityAPI } from '..' import { fetchJSON } from '../helpers' import { GO_PLUS_LABS_ROOT_URL } from './constants' +export interface SupportedChainResponse { + id: string + name: string +} + export class GoPlusLabsAPI implements SecurityAPI.Provider { - async getTokenSecurity(chainId: number, listOfAddress: string[]) { + async getTokenSecurity(chainId: ChainId, listOfAddress: string[]) { const response = await fetchJSON<{ code: 0 | 1 message: 'OK' | string - result: Record + result: Record< + string, + SecurityAPI.ContractSecurity & SecurityAPI.TokenSecurity & SecurityAPI.TradingSecurity + > }>( urlcat(GO_PLUS_LABS_ROOT_URL, 'api/v1/token_security/:id', { id: chainId, @@ -20,4 +29,15 @@ export class GoPlusLabsAPI implements SecurityAPI.Provider { if (response.code !== 1) return return response.result } + + async getSupportedChain(): Promise { + const { code, result } = await fetchJSON<{ + code: 0 | 1 + message: 'OK' | string + result: SupportedChainResponse[] + }>(urlcat(GO_PLUS_LABS_ROOT_URL, 'api/v1/supported_chains')) + + if (code !== 1) return [] + return result.map((x) => ({ id: parseInt(x.id) ?? ChainId.Mainnet, name: x.name })) + } } diff --git a/packages/web3-providers/src/index.ts b/packages/web3-providers/src/index.ts index 37dadc67dfc6..319cb457e9eb 100644 --- a/packages/web3-providers/src/index.ts +++ b/packages/web3-providers/src/index.ts @@ -10,6 +10,7 @@ import { TwitterAPI } from './twitter' import { TokenListAPI } from './token-list' import { TokenPriceAPI } from './token-price' import { InstagramAPI } from './instagram' +import { GoPlusLabsAPI } from './gopluslabs' import { NextIDProofAPI, NextIDStorageAPI } from './NextID' export * from './types' @@ -27,6 +28,8 @@ export const RSS3 = new RSS3API() export const KeyValue = new KeyValueAPI() export const Twitter = new TwitterAPI() export const Instagram = new InstagramAPI() +export const GoPlusLabs = new GoPlusLabsAPI() + export const TokenList = new TokenListAPI() export const TokenPrice = new TokenPriceAPI() export const NextIDStorage = new NextIDStorageAPI() diff --git a/packages/web3-providers/src/types.ts b/packages/web3-providers/src/types.ts index 32259fb1564e..4a3972fb087b 100644 --- a/packages/web3-providers/src/types.ts +++ b/packages/web3-providers/src/types.ts @@ -368,22 +368,39 @@ export namespace NextIDBaseAPI { export namespace SecurityAPI { export interface Holder { address?: string - locked?: 0 | 1 + locked?: '0' | '1' tag?: string - is_contract?: 0 | 1 + is_contract?: '0' | '1' balance?: number percent?: number } + export interface TradingSecurity { + buy_tax?: string + sell_tax?: string + slippage_modifiable?: '0' | '1' + is_honeypot?: '0' | '1' + transfer_pausable?: '0' | '1' + is_blacklisted?: '0' | '1' + is_whitelisted?: '0' | '1' + is_in_dex?: '0' | '1' + is_anti_whale?: '0' | '1' + } + export interface ContractSecurity { - is_open_source?: 0 | 1 - is_proxy?: 0 | 1 - is_mintable?: 0 | 1 - can_take_back_ownership?: string + is_open_source?: '0' | '1' + is_proxy?: '0' | '1' + is_mintable?: '0' | '1' + owner_change_balance?: '0' | '1' + can_take_back_ownership?: '0' | '1' owner_address?: string + creator_address?: string } export interface TokenSecurity { + token_name?: string + token_symbol?: string + holder_count?: number total_supply?: number holders?: Holder[] @@ -392,16 +409,22 @@ export namespace SecurityAPI { lp_total_supply?: number lp_holders?: Holder[] - is_true_token?: 0 | 1 - is_verifiable_team?: 0 | 1 - is_airdrop_scam?: 0 | 1 + is_true_token?: '0' | '1' + is_verifiable_team?: '0' | '1' + is_airdrop_scam?: '0' | '1' + } + + export interface SupportedChain { + id: ChainId + name: string } export interface Provider { getTokenSecurity( chainId: number, listOfAddress: string[], - ): Promise | void> + ): Promise | void> + getSupportedChain(): Promise } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 562f36236d13..de5ff4f87826 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -313,6 +313,7 @@ importers: '@masknet/plugin-example': workspace:* '@masknet/plugin-file-service': workspace:* '@masknet/plugin-flow': workspace:* + '@masknet/plugin-go-plus-security': workspace:* '@masknet/plugin-infra': workspace:* '@masknet/plugin-rss3': workspace:* '@masknet/plugin-solana': workspace:* @@ -451,6 +452,7 @@ importers: '@masknet/plugin-example': link:../plugins/example '@masknet/plugin-file-service': link:../plugins/FileService '@masknet/plugin-flow': link:../plugins/Flow + '@masknet/plugin-go-plus-security': link:../plugins/GoPlusSecurity '@masknet/plugin-infra': link:../plugin-infra '@masknet/plugin-rss3': link:../plugins/RSS3 '@masknet/plugin-solana': link:../plugins/Solana @@ -754,6 +756,34 @@ importers: bignumber.js: 9.0.2 react-use: 17.3.2_581fa33d3647c30d8078674dcd1b240a + packages/plugins/GoPlusSecurity: + specifiers: + '@masknet/icons': workspace:* + '@masknet/plugin-infra': workspace:* + '@masknet/shared': workspace:* + '@masknet/shared-base': workspace:* + '@masknet/shared-base-ui': workspace:* + '@masknet/theme': workspace:* + '@masknet/web3-providers': workspace:* + '@masknet/web3-shared-evm': workspace:* + bignumber.js: ^9.0.2 + react-feather: ^2.0.9 + react-use: ^17.3.2 + urlcat: ^2.0.4 + dependencies: + '@masknet/icons': link:../../icons + '@masknet/plugin-infra': link:../../plugin-infra + '@masknet/shared': link:../../shared + '@masknet/shared-base': link:../../shared-base + '@masknet/shared-base-ui': link:../../shared-base-ui + '@masknet/theme': link:../../theme + '@masknet/web3-providers': link:../../web3-providers + '@masknet/web3-shared-evm': link:../../web3-shared/evm + bignumber.js: 9.0.2 + react-feather: 2.0.9_react@18.0.0 + react-use: 17.3.2_react-dom@18.0.0+react@18.0.0 + urlcat: 2.0.4 + packages/plugins/RSS3: specifiers: '@masknet/icons': workspace:* diff --git a/tsconfig.json b/tsconfig.json index 9d256fb75970..79afc1ef69a4 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -99,6 +99,7 @@ "@masknet/plugin-solana": ["./packages/plugins/Solana/src"], "@masknet/plugin-template": ["./packages/plugins/template/src"], "@masknet/plugin-cyberconnect": ["./packages/plugins/CyberConnect/src"], + "@masknet/plugin-go-plus-security": ["./packages/plugins/GoPlusSecurity/src"], // @masknet/scripts: insert-here 3 "@masknet/plugin-wallet": ["./packages/plugins/Wallet/src"] }, From 77d7ac31e07a8d5297a7e902e935cd5fa127bb89 Mon Sep 17 00:00:00 2001 From: Lantt Date: Wed, 6 Apr 2022 11:04:04 +0800 Subject: [PATCH 21/42] feat: go pocket feedback (#6014) --- packages/plugins/GoPlusSecurity/package.json | 1 - .../src/SNSAdaptor/components/NotFound.tsx | 14 ++++++++++++-- .../src/SNSAdaptor/components/SecurityPanel.tsx | 9 ++++++--- .../src/SNSAdaptor/components/TokenPanel.tsx | 14 +++++--------- .../plugins/GoPlusSecurity/src/locales/en-US.json | 7 ++++++- .../plugins/GoPlusSecurity/src/utils/helper.ts | 3 ++- pnpm-lock.yaml | 2 -- 7 files changed, 31 insertions(+), 19 deletions(-) diff --git a/packages/plugins/GoPlusSecurity/package.json b/packages/plugins/GoPlusSecurity/package.json index 378301090576..602edf644031 100644 --- a/packages/plugins/GoPlusSecurity/package.json +++ b/packages/plugins/GoPlusSecurity/package.json @@ -14,7 +14,6 @@ "@masknet/web3-providers": "workspace:*", "@masknet/web3-shared-evm": "workspace:*", "react-use": "^17.3.2", - "bignumber.js": "^9.0.2", "urlcat": "^2.0.4" } } diff --git a/packages/plugins/GoPlusSecurity/src/SNSAdaptor/components/NotFound.tsx b/packages/plugins/GoPlusSecurity/src/SNSAdaptor/components/NotFound.tsx index 89b95d44e949..20048cad0d13 100644 --- a/packages/plugins/GoPlusSecurity/src/SNSAdaptor/components/NotFound.tsx +++ b/packages/plugins/GoPlusSecurity/src/SNSAdaptor/components/NotFound.tsx @@ -1,3 +1,4 @@ +import { MaskColorVar } from '@masknet/theme' import { Stack, Typography } from '@mui/material' import { useI18N } from '../../locales' @@ -5,8 +6,17 @@ export const NotFound = () => { const t = useI18N() return ( - t.palette.error.main}> - {t.not_found_tip()} + + {t.not_found_tip_title()} + + + {t.not_found_tip_network_error()} + + + {t.not_found_tip_network_chain_correct()} + + + {t.not_found_tip_network_address_not_cover()} ) diff --git a/packages/plugins/GoPlusSecurity/src/SNSAdaptor/components/SecurityPanel.tsx b/packages/plugins/GoPlusSecurity/src/SNSAdaptor/components/SecurityPanel.tsx index 5ea7d29b7c1a..a5ee5c35b44a 100644 --- a/packages/plugins/GoPlusSecurity/src/SNSAdaptor/components/SecurityPanel.tsx +++ b/packages/plugins/GoPlusSecurity/src/SNSAdaptor/components/SecurityPanel.tsx @@ -86,7 +86,6 @@ export const SecurityPanel = memo(({ tokenSecurity }) => { lineHeight="14px" href={resolveGoLabLink(tokenSecurity.chainId, tokenSecurity.contract)} target="_blank" - title={t.more_details()} rel="noopener noreferrer"> @@ -106,7 +105,9 @@ export const SecurityPanel = memo(({ tokenSecurity }) => { {DefineMapping[SecurityMessageLevel.High].icon(14)} - {t.risky_factors({ quantity: riskyFactors.toString() })} + {riskyFactors > 1 + ? t.risky_factors({ quantity: riskyFactors.toString() }) + : t.risky_factor({ quantity: riskyFactors.toString() })} )} @@ -114,7 +115,9 @@ export const SecurityPanel = memo(({ tokenSecurity }) => { {DefineMapping[SecurityMessageLevel.Medium].icon(14)} - {t.attention_factors({ quantity: attentionFactors.toString() })} + {attentionFactors > 1 + ? t.attention_factors({ quantity: attentionFactors.toString() }) + : t.attention_factor({ quantity: attentionFactors.toString() })} )} diff --git a/packages/plugins/GoPlusSecurity/src/SNSAdaptor/components/TokenPanel.tsx b/packages/plugins/GoPlusSecurity/src/SNSAdaptor/components/TokenPanel.tsx index fc17746b810f..3844db22dddd 100644 --- a/packages/plugins/GoPlusSecurity/src/SNSAdaptor/components/TokenPanel.tsx +++ b/packages/plugins/GoPlusSecurity/src/SNSAdaptor/components/TokenPanel.tsx @@ -1,14 +1,13 @@ import { Link, Stack, Tooltip, Typography } from '@mui/material' import { DefineMapping, SecurityMessageLevel, TokenSecurity } from './Common' -import parseInt from 'lodash-es/parseInt' import { useI18N } from '../../locales' import React from 'react' import { useTheme } from '@mui/system' import { ExternalLink } from 'react-feather' import { makeStyles, usePortalShadowRoot } from '@masknet/theme' -import BigNumber from 'bignumber.js' import { ERC20Token, + formatCurrency, formatEthereumAddress, resolveAddressLinkOnExplorer, resolveTokenLinkOnExplorer, @@ -41,7 +40,7 @@ const DEFAULT_PLACEHOLDER = '--' function formatTotalSupply(total?: number) { if (!total) return DEFAULT_PLACEHOLDER - return new BigNumber(total).toFormat(3) + return formatCurrency(total) } interface TokenPanelProps { @@ -103,11 +102,10 @@ export const TokenPanel = React.forwardRef(({ tokenSecurity, securityMessageLeve @@ -125,11 +123,10 @@ export const TokenPanel = React.forwardRef(({ tokenSecurity, securityMessageLeve @@ -148,11 +145,10 @@ export const TokenPanel = React.forwardRef(({ tokenSecurity, securityMessageLeve diff --git a/packages/plugins/GoPlusSecurity/src/locales/en-US.json b/packages/plugins/GoPlusSecurity/src/locales/en-US.json index 9f208758c4c5..737a020e8cfe 100644 --- a/packages/plugins/GoPlusSecurity/src/locales/en-US.json +++ b/packages/plugins/GoPlusSecurity/src/locales/en-US.json @@ -11,6 +11,8 @@ "security_detection": "Security Detection", "risky_factors": "{{quantity}} Risky factors", "attention_factors": "{{quantity}} Attention factors", + "risky_factor": "{{quantity}} Risky factor", + "attention_factor": "{{quantity}} Attention factor", "security_info_code_not_verify_title": "Contract source code not verified", "security_info_code_not_verify_message": "This token contract has not been verified. We cannot check the contract code for details. Unsourced token contracts are likely to have malicious functions to defraud users of their assets", "security_info_functions_that_can_suspend_trading_title": "Functions that can suspend trading", @@ -21,7 +23,10 @@ "token_info_contract_owner": "Contract Owner", "token_info_total_supply": "Total Supply", "default_placeholder": "Note: Scams detections might not be 100% guaranteed.", - "not_found_tip": "Network error or the on-chain data is abnormal. Please switch to the correct network or check the address again.", + "not_found_tip_title": "Results not found now. it might be chain network error, on-chain data abnormal or the token address is not covered now. please check as followings:", + "not_found_tip_network_error": "1. Make sure network is working;", + "not_found_tip_network_chain_correct": "2. Mask sure the chain network or token address is correct;", + "not_found_tip_network_address_not_cover": "3. Token address is not covered now, it might take more than 60s to get contract information again. Please try it later.", "risk_safe_description": "This token has no risky or attention factors.", "risk_contract_source_code_verified_title": "Contract source code verified", "risk_contract_source_code_verified_body": "This token contract is open source. You can check the contract code for details. Unsourced token contracts are likely to have malicious functions to defraud their users of their assets.", diff --git a/packages/plugins/GoPlusSecurity/src/utils/helper.ts b/packages/plugins/GoPlusSecurity/src/utils/helper.ts index a1d47642fe4a..39d6c594a73c 100644 --- a/packages/plugins/GoPlusSecurity/src/utils/helper.ts +++ b/packages/plugins/GoPlusSecurity/src/utils/helper.ts @@ -1,5 +1,6 @@ +import type { ChainId } from '@masknet/web3-shared-evm' import urlcat from 'urlcat' -export function resolveGoLabLink(chainId: string, address: string) { +export function resolveGoLabLink(chainId: ChainId, address: string) { return urlcat('https://gopluslabs.io/token-security/:chainId/:address', { chainId, address }) } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index de5ff4f87826..9ce2ea8bc71d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -766,7 +766,6 @@ importers: '@masknet/theme': workspace:* '@masknet/web3-providers': workspace:* '@masknet/web3-shared-evm': workspace:* - bignumber.js: ^9.0.2 react-feather: ^2.0.9 react-use: ^17.3.2 urlcat: ^2.0.4 @@ -779,7 +778,6 @@ importers: '@masknet/theme': link:../../theme '@masknet/web3-providers': link:../../web3-providers '@masknet/web3-shared-evm': link:../../web3-shared/evm - bignumber.js: 9.0.2 react-feather: 2.0.9_react@18.0.0 react-use: 17.3.2_react-dom@18.0.0+react@18.0.0 urlcat: 2.0.4 From 3e6a7e7ab3dd360ac1397157ad2ca8375b1b2a12 Mon Sep 17 00:00:00 2001 From: Lantt Date: Wed, 6 Apr 2022 12:27:22 +0800 Subject: [PATCH 22/42] fix: should update tip status when next id verify status changed (#6020) * fix: should update tip status when next id verify status changed * refactor: code review feedback --- .../plugins/NextID/components/BindDialog.tsx | 4 ++ .../NextID/components/Tip/TipButton.tsx | 16 ++++++- .../NextID/components/UnbindDialog.tsx | 4 ++ packages/web3-providers/src/NextID/helper.ts | 4 ++ packages/web3-providers/src/NextID/proof.ts | 45 ++++++++++++------- 5 files changed, 54 insertions(+), 19 deletions(-) diff --git a/packages/mask/src/plugins/NextID/components/BindDialog.tsx b/packages/mask/src/plugins/NextID/components/BindDialog.tsx index e5e3698a0a94..4879f7f3e952 100644 --- a/packages/mask/src/plugins/NextID/components/BindDialog.tsx +++ b/packages/mask/src/plugins/NextID/components/BindDialog.tsx @@ -13,6 +13,7 @@ import { useBindPayload } from '../hooks/useBindPayload' import { usePersonaSign } from '../hooks/usePersonaSign' import { useWalletSign } from '../hooks/useWalletSign' import { NextIDProof } from '@masknet/web3-providers' +import { MaskMessages } from '../../../../shared' interface BindDialogProps { open: boolean @@ -52,6 +53,9 @@ export const BindDialog = memo(({ open, onClose, persona, onBou variant: 'success', message: t.notify_wallet_sign_request_success(), }) + + MaskMessages.events.ownProofChanged.sendToAll() + await delay(2000) onBound() onClose() diff --git a/packages/mask/src/plugins/NextID/components/Tip/TipButton.tsx b/packages/mask/src/plugins/NextID/components/Tip/TipButton.tsx index 04daf94ccd45..95cd6efcfe66 100644 --- a/packages/mask/src/plugins/NextID/components/Tip/TipButton.tsx +++ b/packages/mask/src/plugins/NextID/components/Tip/TipButton.tsx @@ -7,12 +7,13 @@ import { EMPTY_LIST } from '@masknet/web3-shared-evm' import type { TooltipProps } from '@mui/material' import classnames from 'classnames' import { uniq } from 'lodash-unified' -import { FC, HTMLProps, MouseEventHandler, useCallback, useMemo } from 'react' +import { FC, HTMLProps, MouseEventHandler, useCallback, useEffect, useMemo } from 'react' import { useAsync, useAsyncFn, useAsyncRetry } from 'react-use' import Services from '../../../../extension/service' import { activatedSocialNetworkUI } from '../../../../social-network' import { useI18N } from '../../locales' import { PluginNextIdMessages } from '../../messages' +import { MaskMessages } from '../../../../../shared' interface Props extends HTMLProps { addresses?: string[] @@ -72,7 +73,11 @@ export const TipButton: FC = ({ return Services.Identity.queryPersonaByProfile(receiver) }, [receiver]) - const { value: isAccountVerified, loading: loadingVerifyInfo } = useAsync(() => { + const { + value: isAccountVerified, + loading: loadingVerifyInfo, + retry: retryLoadVerifyInfo, + } = useAsyncRetry(() => { if (!receiverPersona?.publicHexKey || !receiver?.userId) return Promise.resolve(false) return NextIDProof.queryIsBound(receiverPersona.publicHexKey, platform, receiver.userId, true) }, [receiverPersona?.publicHexKey, platform, receiver?.userId]) @@ -92,6 +97,13 @@ export const TipButton: FC = ({ useAsync(queryBindings, [queryBindings]) + useEffect(() => { + return MaskMessages.events.ownProofChanged.on(() => { + retryLoadVerifyInfo() + queryBindings() + }) + }, []) + const allAddresses = useMemo(() => { return uniq([...(walletsState.value || []), ...addresses]) }, [walletsState.value, addresses]) diff --git a/packages/mask/src/plugins/NextID/components/UnbindDialog.tsx b/packages/mask/src/plugins/NextID/components/UnbindDialog.tsx index aadc5dc1cf72..cc0b95ba29b0 100644 --- a/packages/mask/src/plugins/NextID/components/UnbindDialog.tsx +++ b/packages/mask/src/plugins/NextID/components/UnbindDialog.tsx @@ -13,6 +13,7 @@ import { delay } from '@dimensiondev/kit' import { UnbindPanelUI } from './UnbindPanelUI' import { UnbindConfirm } from './UnbindConfirm' import { NextIDProof } from '@masknet/web3-providers' +import { MaskMessages } from '../../../../shared' interface VerifyWalletDialogProps { unbindAddress: string @@ -56,6 +57,9 @@ export const UnbindDialog = memo(({ unbindAddress, onCl variant: 'success', message: t.notify_wallet_sign_request_success(), }) + + MaskMessages.events.ownProofChanged.sendToAll() + await delay(2000) onUnBound() onClose() diff --git a/packages/web3-providers/src/NextID/helper.ts b/packages/web3-providers/src/NextID/helper.ts index 560e3c9d8363..0708e8ce7e3c 100644 --- a/packages/web3-providers/src/NextID/helper.ts +++ b/packages/web3-providers/src/NextID/helper.ts @@ -6,6 +6,10 @@ const fetchCache = new LRU({ ttl: 20000, }) +export function deleteCache(key: string) { + fetchCache.delete(key) +} + export async function fetchJSON( url: string, requestInit?: RequestInit, diff --git a/packages/web3-providers/src/NextID/proof.ts b/packages/web3-providers/src/NextID/proof.ts index 7f126278fce9..6a134c0e4d42 100644 --- a/packages/web3-providers/src/NextID/proof.ts +++ b/packages/web3-providers/src/NextID/proof.ts @@ -1,4 +1,4 @@ -import { fetchJSON } from './helper' +import { deleteCache, fetchJSON } from './helper' import urlcat from 'urlcat' import { first } from 'lodash-unified' import { @@ -32,9 +32,22 @@ interface CreatePayloadResponse { created_at: string } +const getPersonaQueryURL = (platform: string, identity: string) => + urlcat(BASE_URL, '/v1/proof', { + platform, + identity, + }) + +const geyExistedBindingQueryURL = (platform: string, identity: string, personaPublicKey: string) => + urlcat(BASE_URL, '/v1/proof/exists', { + platform, + identity, + public_key: personaPublicKey, + }) + export class NextIDProofAPI implements NextIDBaseAPI.Proof { // TODO: remove 'bind' in project for business context. - bindProof( + async bindProof( uuid: string, personaPublicKey: string, action: NextIDAction, @@ -61,18 +74,23 @@ export class NextIDProofAPI implements NextIDBaseAPI.Proof { created_at: createdAt, } - return fetchJSON(urlcat(BASE_URL, '/v1/proof'), { + const result = await fetchJSON(urlcat(BASE_URL, '/v1/proof'), { body: JSON.stringify(requestBody), method: 'POST', }) + + // Should delete cache when proof status changed + const cacheKeyOfQueryPersona = getPersonaQueryURL(NextIDPlatform.NextId, personaPublicKey) + const cacheKeyOfExistedBinding = geyExistedBindingQueryURL(platform, identity, personaPublicKey) + deleteCache(cacheKeyOfQueryPersona) + deleteCache(cacheKeyOfExistedBinding) + + return result } async queryExistedBindingByPersona(personaPublicKey: string, enableCache?: boolean) { - const response = await fetchJSON( - urlcat(BASE_URL, '/v1/proof', { platform: NextIDPlatform.NextId, identity: personaPublicKey }), - {}, - enableCache, - ) + const url = getPersonaQueryURL(NextIDPlatform.NextId, personaPublicKey) + const response = await fetchJSON(url, {}, enableCache) // Will have only one item when query by personaPublicKey return first(response.unwrap().ids) } @@ -91,15 +109,8 @@ export class NextIDProofAPI implements NextIDBaseAPI.Proof { async queryIsBound(personaPublicKey: string, platform: NextIDPlatform, identity: string, enableCache?: boolean) { if (!platform && !identity) return false - const result = await fetchJSON( - urlcat(BASE_URL, '/v1/proof/exists', { - platform: platform, - identity: identity, - public_key: personaPublicKey, - }), - {}, - enableCache, - ) + const url = geyExistedBindingQueryURL(platform, identity, personaPublicKey) + const result = await fetchJSON(url, {}, enableCache) return result.map(() => true).unwrapOr(false) } From 644339b752c5de39928bd6931c5bc21eb7c7b292 Mon Sep 17 00:00:00 2001 From: Lantt Date: Wed, 6 Apr 2022 15:27:57 +0800 Subject: [PATCH 23/42] fix: lock file --- pnpm-lock.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9ce2ea8bc71d..ce04eb270ac0 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -778,8 +778,8 @@ importers: '@masknet/theme': link:../../theme '@masknet/web3-providers': link:../../web3-providers '@masknet/web3-shared-evm': link:../../web3-shared/evm - react-feather: 2.0.9_react@18.0.0 - react-use: 17.3.2_react-dom@18.0.0+react@18.0.0 + react-feather: 2.0.9_react@18.0.0-rc.3 + react-use: 17.3.2_581fa33d3647c30d8078674dcd1b240a urlcat: 2.0.4 packages/plugins/RSS3: From 4be9adfa836397ef121217210375fc98f75cef6f Mon Sep 17 00:00:00 2001 From: UncleBill Date: Thu, 31 Mar 2022 14:47:43 +0800 Subject: [PATCH 24/42] fix(share): popup share (#6003) --- .../src/social-network-adaptor/twitter.com/shared.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/mask/src/social-network-adaptor/twitter.com/shared.ts b/packages/mask/src/social-network-adaptor/twitter.com/shared.ts index 1b1ce5795335..f971f7549c1b 100644 --- a/packages/mask/src/social-network-adaptor/twitter.com/shared.ts +++ b/packages/mask/src/social-network-adaptor/twitter.com/shared.ts @@ -36,7 +36,14 @@ export const twitterShared: SocialNetwork.Shared & SocialNetwork.Base = { height, screenX: window.screenX + (window.innerWidth - width) / 2, screenY: window.screenY + (window.innerHeight - height) / 2, - behaviors: { toolbar: true, status: true, resizable: true, scrollbars: true }, + opener: true, + referrer: true, + behaviors: { + toolbar: true, + status: true, + resizable: true, + scrollbars: true, + }, }) if (openedWindow === null) { location.assign(url) From a509e91f1b244165adab58f4cc7839fac242590e Mon Sep 17 00:00:00 2001 From: Jack Works Date: Wed, 30 Mar 2022 15:51:40 +0800 Subject: [PATCH 25/42] refactor: move MAX_PERSONA_LIMIT and formatPersonaFingerprint --- .../Personas/components/PersonaCard/index.tsx | 14 +++++++------- .../Personas/components/PersonaDrawer/index.tsx | 3 +-- .../Personas/components/PersonaStateBar/index.tsx | 4 ++-- .../extension/popups/pages/Personas/Home/index.tsx | 5 ++--- .../popups/pages/Personas/Logout/index.tsx | 6 ++---- .../Personas/components/DisconnectDialog/index.tsx | 6 +++--- .../Personas/components/PersonaList/index.tsx | 11 +++++++---- .../src/plugins/NextID/components/BindPanelUI.tsx | 5 +++-- .../plugins/NextID/components/UnbindPanelUI.tsx | 5 +++-- packages/shared-base/src/utils/index.ts | 1 + .../src/utils/personas.ts} | 3 ++- packages/shared/src/constants.tsx | 1 - packages/shared/src/index.ts | 1 - packages/shared/src/utils/index.ts | 1 - 14 files changed, 33 insertions(+), 33 deletions(-) rename packages/{shared/src/utils/formatter.ts => shared-base/src/utils/personas.ts} (52%) delete mode 100644 packages/shared/src/utils/index.ts diff --git a/packages/dashboard/src/pages/Personas/components/PersonaCard/index.tsx b/packages/dashboard/src/pages/Personas/components/PersonaCard/index.tsx index ad1badae8cb2..e3faaa4fd2a2 100644 --- a/packages/dashboard/src/pages/Personas/components/PersonaCard/index.tsx +++ b/packages/dashboard/src/pages/Personas/components/PersonaCard/index.tsx @@ -2,13 +2,13 @@ import { memo } from 'react' import { makeStyles, MaskColorVar } from '@masknet/theme' import { Typography } from '@mui/material' import { ConnectedPersonaLine, UnconnectedPersonaLine } from '../PersonaLine' -import type { - NextIDPersonaBindings, - PersonaIdentifier, - ProfileIdentifier, - ProfileInformation, +import { + type NextIDPersonaBindings, + type PersonaIdentifier, + type ProfileIdentifier, + type ProfileInformation, + formatPersonaFingerprint, } from '@masknet/shared-base' -import { formatFingerprint } from '@masknet/shared' import { PersonaContext } from '../../hooks/usePersonaContext' import type { SocialNetwork } from '../../api' import classNames from 'classnames' @@ -103,7 +103,7 @@ export const PersonaCardUI = memo((props) => { {nickname} - {formatFingerprint(identifier.compressedPoint, 4)} + {formatPersonaFingerprint(identifier.compressedPoint, 4)}
diff --git a/packages/dashboard/src/pages/Personas/components/PersonaDrawer/index.tsx b/packages/dashboard/src/pages/Personas/components/PersonaDrawer/index.tsx index a28f8b73a0ea..18e605f82a87 100644 --- a/packages/dashboard/src/pages/Personas/components/PersonaDrawer/index.tsx +++ b/packages/dashboard/src/pages/Personas/components/PersonaDrawer/index.tsx @@ -4,9 +4,8 @@ import { makeStyles, MaskColorVar } from '@masknet/theme' import { PersonaContext } from '../../hooks/usePersonaContext' import { PersonaCard } from '../PersonaCard' import { useDashboardI18N } from '../../../../locales' -import { PersonaIdentifier, PersonaInformation, DashboardRoutes } from '@masknet/shared-base' +import { PersonaIdentifier, PersonaInformation, DashboardRoutes, MAX_PERSONA_LIMIT } from '@masknet/shared-base' import { useNavigate } from 'react-router-dom' -import { MAX_PERSONA_LIMIT } from '@masknet/shared' const useStyles = makeStyles()((theme) => ({ paper: { diff --git a/packages/dashboard/src/pages/Personas/components/PersonaStateBar/index.tsx b/packages/dashboard/src/pages/Personas/components/PersonaStateBar/index.tsx index 8f288d399dfc..ac078f2f144d 100644 --- a/packages/dashboard/src/pages/Personas/components/PersonaStateBar/index.tsx +++ b/packages/dashboard/src/pages/Personas/components/PersonaStateBar/index.tsx @@ -3,7 +3,7 @@ import { Box, IconButton, Stack, Typography } from '@mui/material' import { MaskAvatar } from '../../../../components/MaskAvatar' import { ArrowDownRound, ArrowUpRound } from '@masknet/icons' import { makeStyles, MaskColorVar } from '@masknet/theme' -import { formatFingerprint } from '@masknet/shared' +import { formatPersonaFingerprint } from '@masknet/shared-base' const useStyles = makeStyles()((theme) => ({ iconButton: { @@ -43,7 +43,7 @@ export const PersonaStateBar = memo(({ nickname, toggleDra {nickname} - {formatFingerprint(fingerprint ?? '', 6)} + {formatPersonaFingerprint(fingerprint ?? '', 6)} diff --git a/packages/mask/src/extension/popups/pages/Personas/Home/index.tsx b/packages/mask/src/extension/popups/pages/Personas/Home/index.tsx index 2783893dbbcd..f9e0ab588bca 100644 --- a/packages/mask/src/extension/popups/pages/Personas/Home/index.tsx +++ b/packages/mask/src/extension/popups/pages/Personas/Home/index.tsx @@ -4,8 +4,7 @@ import { PersonaContext } from '../hooks/usePersonaContext' import { useNavigate } from 'react-router-dom' import { DeleteIcon, MasksIcon, EditIcon } from '@masknet/icons' import { Button, Typography } from '@mui/material' -import { formatFingerprint, MAX_PERSONA_LIMIT } from '@masknet/shared' -import { PopupRoutes } from '@masknet/shared-base' +import { PopupRoutes, formatPersonaFingerprint, MAX_PERSONA_LIMIT } from '@masknet/shared-base' import { ChevronDown, ChevronUp } from 'react-feather' import { ProfileList } from '../components/ProfileList' import { EnterDashboard } from '../../../components/EnterDashboard' @@ -114,7 +113,7 @@ const PersonaHome = memo(() => { /> - {formatFingerprint(currentPersona?.identifier.compressedPoint ?? '', 10)} + {formatPersonaFingerprint(currentPersona?.identifier.compressedPoint ?? '', 10)} { diff --git a/packages/mask/src/extension/popups/pages/Personas/Logout/index.tsx b/packages/mask/src/extension/popups/pages/Personas/Logout/index.tsx index a36d617fe1bb..8b32d2fd38fa 100644 --- a/packages/mask/src/extension/popups/pages/Personas/Logout/index.tsx +++ b/packages/mask/src/extension/popups/pages/Personas/Logout/index.tsx @@ -8,9 +8,7 @@ import { PersonaContext } from '../hooks/usePersonaContext' import Services from '../../../../service' import { LoadingButton } from '@mui/lab' import { useNavigate } from 'react-router-dom' -import { PopupRoutes } from '@masknet/shared-base' -import type { PersonaInformation } from '@masknet/shared-base' -import { formatFingerprint } from '@masknet/shared' +import { PopupRoutes, formatPersonaFingerprint, type PersonaInformation } from '@masknet/shared-base' import { PasswordField } from '../../../components/PasswordField' const useStyles = makeStyles()((theme) => ({ @@ -147,7 +145,7 @@ export const LogoutUI = memo(({ backupPassword, loading, onLogout
{deletingPersona?.nickname} - {formatFingerprint(deletingPersona?.identifier.compressedPoint ?? '', 10)} + {formatPersonaFingerprint(deletingPersona?.identifier.compressedPoint ?? '', 10)}
diff --git a/packages/mask/src/extension/popups/pages/Personas/components/DisconnectDialog/index.tsx b/packages/mask/src/extension/popups/pages/Personas/components/DisconnectDialog/index.tsx index 7401e743c323..381b349871f2 100644 --- a/packages/mask/src/extension/popups/pages/Personas/components/DisconnectDialog/index.tsx +++ b/packages/mask/src/extension/popups/pages/Personas/components/DisconnectDialog/index.tsx @@ -2,8 +2,7 @@ import { memo } from 'react' import { Button, Dialog, DialogActions, DialogContent, Typography, DialogProps } from '@mui/material' import { makeStyles } from '@masknet/theme' import classNames from 'classnames' -import type { ProfileIdentifier } from '@masknet/shared-base' -import { formatFingerprint } from '@masknet/shared' +import { formatPersonaFingerprint, type ProfileIdentifier } from '@masknet/shared-base' import { PersonaContext } from '../../hooks/usePersonaContext' import { LoadingButton } from '@mui/lab' import { useI18N } from '../../../../../../utils' @@ -71,7 +70,8 @@ export const DisconnectDialog = memo( {t('popups_persona_disconnect_confirmation_description')} - {t('popups_persona')}: {formatFingerprint(currentPersona?.identifier.compressedPoint ?? '', 10)} + {t('popups_persona')}:{' '} + {formatPersonaFingerprint(currentPersona?.identifier.compressedPoint ?? '', 10)}
{t('popups_twitter_id')}: @{unbundledIdentity.userId}
diff --git a/packages/mask/src/extension/popups/pages/Personas/components/PersonaList/index.tsx b/packages/mask/src/extension/popups/pages/Personas/components/PersonaList/index.tsx index 3d46091d664d..332f162fee70 100644 --- a/packages/mask/src/extension/popups/pages/Personas/components/PersonaList/index.tsx +++ b/packages/mask/src/extension/popups/pages/Personas/components/PersonaList/index.tsx @@ -1,11 +1,14 @@ import { memo, useCallback } from 'react' import { makeStyles } from '@masknet/theme' import { PersonaContext } from '../../hooks/usePersonaContext' -import type { PersonaInformation, ECKeyIdentifier } from '@masknet/shared-base' +import { + formatPersonaFingerprint, + PopupRoutes, + type PersonaInformation, + type ECKeyIdentifier, +} from '@masknet/shared-base' import { ListItemButton, List, Typography } from '@mui/material' import { DeleteIcon, MasksIcon } from '@masknet/icons' -import { formatFingerprint } from '@masknet/shared' -import { PopupRoutes } from '@masknet/shared-base' import { useNavigate } from 'react-router-dom' import Services from '../../../../../service' @@ -95,7 +98,7 @@ export const PersonaListUI = memo(({ personas, onLogout, onC
{nickname} - {formatFingerprint(identifier.compressedPoint ?? '', 10)} + {formatPersonaFingerprint(identifier.compressedPoint ?? '', 10)} { diff --git a/packages/mask/src/plugins/NextID/components/BindPanelUI.tsx b/packages/mask/src/plugins/NextID/components/BindPanelUI.tsx index b146fb5fea1e..74b2cc741ca2 100644 --- a/packages/mask/src/plugins/NextID/components/BindPanelUI.tsx +++ b/packages/mask/src/plugins/NextID/components/BindPanelUI.tsx @@ -7,7 +7,8 @@ import DoneIcon from '@mui/icons-material/Done' import { useI18N } from '../locales' import { getMaskColor, makeStyles, MaskColorVar } from '@masknet/theme' import type { Persona } from '../../../database' -import { formatFingerprint, LoadingAnimation } from '@masknet/shared' +import { LoadingAnimation } from '@masknet/shared' +import { formatPersonaFingerprint } from '@masknet/shared-base' import { InjectedDialog } from '../../../components/shared/InjectedDialog' import { NetworkPluginID, useCurrentWeb3NetworkPluginID } from '@masknet/plugin-infra' @@ -162,7 +163,7 @@ export const BindPanelUI = memo(
{currentPersona?.nickname} - {formatFingerprint(currentPersona?.identifier.compressedPoint ?? '', 10)} + {formatPersonaFingerprint(currentPersona?.identifier.compressedPoint ?? '', 10)}
diff --git a/packages/mask/src/plugins/NextID/components/UnbindPanelUI.tsx b/packages/mask/src/plugins/NextID/components/UnbindPanelUI.tsx index 0b16db064a83..c54656b32760 100644 --- a/packages/mask/src/plugins/NextID/components/UnbindPanelUI.tsx +++ b/packages/mask/src/plugins/NextID/components/UnbindPanelUI.tsx @@ -7,7 +7,8 @@ import DoneIcon from '@mui/icons-material/Done' import { useI18N } from '../locales' import { getMaskColor, makeStyles, MaskColorVar } from '@masknet/theme' import type { Persona } from '../../../database' -import { formatFingerprint, LoadingAnimation } from '@masknet/shared' +import { LoadingAnimation } from '@masknet/shared' +import { formatPersonaFingerprint } from '@masknet/shared-base' import { InjectedDialog } from '../../../components/shared/InjectedDialog' import { NetworkPluginID, useCurrentWeb3NetworkPluginID } from '@masknet/plugin-infra' import AbstractTab, { AbstractTabProps } from '../../../components/shared/AbstractTab' @@ -116,7 +117,7 @@ export const UnbindPanelUI = memo(
{currentPersona?.nickname} - {formatFingerprint(currentPersona?.identifier.compressedPoint ?? '', 10)} + {formatPersonaFingerprint(currentPersona?.identifier.compressedPoint ?? '', 10)}
diff --git a/packages/shared-base/src/utils/index.ts b/packages/shared-base/src/utils/index.ts index 72ecac83030b..ebbcc29848cc 100644 --- a/packages/shared-base/src/utils/index.ts +++ b/packages/shared-base/src/utils/index.ts @@ -5,3 +5,4 @@ export * from './pollingTask' export * from './sessionStorageCache' export * from './subscription' export * from './getAssetAsBlobURL' +export * from './personas' diff --git a/packages/shared/src/utils/formatter.ts b/packages/shared-base/src/utils/personas.ts similarity index 52% rename from packages/shared/src/utils/formatter.ts rename to packages/shared-base/src/utils/personas.ts index 919f1fba7940..08af447a1f79 100644 --- a/packages/shared/src/utils/formatter.ts +++ b/packages/shared-base/src/utils/personas.ts @@ -1,4 +1,5 @@ -export function formatFingerprint(fingerprint: string, size = 0) { +export function formatPersonaFingerprint(fingerprint: string, size = 0) { if (size === 0) return fingerprint return `${fingerprint.substr(0, 2 + size)}...${fingerprint.substr(-size)}` } +export const MAX_PERSONA_LIMIT = 10 diff --git a/packages/shared/src/constants.tsx b/packages/shared/src/constants.tsx index b11fc21698e8..839fb817c6b4 100644 --- a/packages/shared/src/constants.tsx +++ b/packages/shared/src/constants.tsx @@ -18,4 +18,3 @@ export const SOCIAL_MEDIA_ICON_MAPPING: Record = { export const mediaViewerUrl = 'https://media-viewer.r2d2.to/index.html' export const MAX_WALLET_LIMIT = 100 -export const MAX_PERSONA_LIMIT = 10 diff --git a/packages/shared/src/index.ts b/packages/shared/src/index.ts index a552a39b2942..832ef31a6879 100644 --- a/packages/shared/src/index.ts +++ b/packages/shared/src/index.ts @@ -3,7 +3,6 @@ export * from './wallet' export * from './UI' export * from './locales' export * from './locales/languages' -export * from './utils' export * from './constants' // This interface is used as a proxy type to avoid circular project dependencies export interface DashboardPluginMessages { diff --git a/packages/shared/src/utils/index.ts b/packages/shared/src/utils/index.ts deleted file mode 100644 index 80c86669067a..000000000000 --- a/packages/shared/src/utils/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './formatter' From f153ba81d4bbbdf6d559954e2042312942e5ad36 Mon Sep 17 00:00:00 2001 From: guanbinrui <52657989+guanbinrui@users.noreply.github.com> Date: Fri, 25 Mar 2022 14:52:13 +0800 Subject: [PATCH 26/42] refactor: reduce rerendering (#5952) * fix: a CSS warning * refactor: pure values * fix: typo * refactor: enums * fix: lint error --- .../components/CollectibleList/index.tsx | 5 +- .../components/WalletStateBar/index.tsx | 3 +- .../components/DataSource/useActivatedUI.ts | 4 +- .../InjectedComponents/ProfileTabContent.tsx | 3 +- .../Collectible/SNSAdaptor/Collectible.tsx | 6 +- .../Collectible/hooks/useAssetOrder.ts | 4 +- .../src/plugins/NextID/SNSAdaptor/index.tsx | 2 +- .../NextID/components/Tip/TipButton.tsx | 5 +- .../NextID/components/Tip/TipDialog.tsx | 3 +- .../NextID/components/Tip/TipTaskManager.tsx | 2 +- .../Savings/SNSAdaptor/SavingsDialog.tsx | 3 +- .../plugins/Trader/trader/uniswap/usePairs.ts | 4 +- .../Trader/trader/useAllTradeComputed.ts | 3 +- .../utils/create-post-context.ts | 10 +- packages/mask/utils-pure/index.ts | 1 - .../plugins/RSS3/src/SNSAdaptor/TabCard.tsx | 3 +- .../RSS3/src/SNSAdaptor/hooks/useDonations.ts | 2 +- packages/polyfills/types/env.d.ts | 1 + packages/public-api/src/web.ts | 71 ++++++++---- packages/shared-base/package.json | 1 + packages/shared-base/src/Messages/Mask.ts | 12 ++- .../misc.ts => shared-base/src/Pure/index.ts} | 0 packages/shared-base/src/index.ts | 1 + packages/shared-base/tsconfig.json | 2 +- packages/theme/package.json | 1 + .../ShadowRoot/createReactRootShadowed.tsx | 5 +- packages/theme/tsconfig.json | 2 +- packages/web3-shared/base/src/utils/number.ts | 1 + packages/web3-shared/evm/hooks/useAssets.ts | 3 +- .../evm/hooks/useAssetsFromChain.ts | 3 +- .../web3-shared/evm/hooks/useAssetsMerged.ts | 5 +- .../web3-shared/evm/hooks/useTokensBalance.ts | 4 +- packages/web3-shared/evm/tsconfig.json | 2 +- packages/web3-shared/evm/types/index.ts | 102 +++++++++--------- packages/web3-shared/evm/utils/address.ts | 4 +- packages/web3-shared/evm/utils/index.ts | 1 - packages/web3-shared/flow/tsconfig.json | 2 +- pnpm-lock.yaml | 4 + 38 files changed, 171 insertions(+), 119 deletions(-) rename packages/{mask/utils-pure/misc.ts => shared-base/src/Pure/index.ts} (100%) diff --git a/packages/dashboard/src/pages/Wallets/components/CollectibleList/index.tsx b/packages/dashboard/src/pages/Wallets/components/CollectibleList/index.tsx index 58fae8cd29ef..d6834fbed62e 100644 --- a/packages/dashboard/src/pages/Wallets/components/CollectibleList/index.tsx +++ b/packages/dashboard/src/pages/Wallets/components/CollectibleList/index.tsx @@ -1,14 +1,13 @@ import { Dispatch, memo, SetStateAction, useCallback, useEffect, useRef, useState } from 'react' +import { useNavigate } from 'react-router-dom' import { Box, Stack, TablePagination } from '@mui/material' import { makeStyles } from '@masknet/theme' -import { EMPTY_LIST } from '@masknet/web3-shared-evm' import { LoadingPlaceholder } from '../../../../components/LoadingPlaceholder' +import { DashboardRoutes, EMPTY_LIST } from '@masknet/shared-base' import { EmptyPlaceholder } from '../EmptyPlaceholder' import { CollectibleCard } from '../CollectibleCard' import { useDashboardI18N } from '../../../../locales' import { PluginMessages } from '../../../../API' -import { useNavigate } from 'react-router-dom' -import { DashboardRoutes } from '@masknet/shared-base' import { TransferTab } from '../Transfer' import { useNetworkDescriptor, diff --git a/packages/dashboard/src/pages/Wallets/components/WalletStateBar/index.tsx b/packages/dashboard/src/pages/Wallets/components/WalletStateBar/index.tsx index 6b93fbc3013a..574dd8689708 100644 --- a/packages/dashboard/src/pages/Wallets/components/WalletStateBar/index.tsx +++ b/packages/dashboard/src/pages/Wallets/components/WalletStateBar/index.tsx @@ -1,6 +1,6 @@ import { FC, memo } from 'react' import { Box, Button, Stack, Typography } from '@mui/material' -import { EMPTY_LIST, ProviderType, TransactionStatusType } from '@masknet/web3-shared-evm' +import { ProviderType, TransactionStatusType } from '@masknet/web3-shared-evm' import { makeStyles, MaskColorVar } from '@masknet/theme' import { FormattedAddress, LoadingAnimation, WalletIcon } from '@masknet/shared' import { useRemoteControlledDialog } from '@masknet/shared-base-ui' @@ -12,6 +12,7 @@ import { Web3Plugin, useReverseAddress, } from '@masknet/plugin-infra' +import { EMPTY_LIST } from '@masknet/shared-base' import { PluginMessages } from '../../../../API' import { useRecentTransactions } from '../../hooks/useRecentTransactions' import { useDashboardI18N } from '../../../../locales' diff --git a/packages/mask/src/components/DataSource/useActivatedUI.ts b/packages/mask/src/components/DataSource/useActivatedUI.ts index a829094b54ff..c5cef6e522c4 100644 --- a/packages/mask/src/components/DataSource/useActivatedUI.ts +++ b/packages/mask/src/components/DataSource/useActivatedUI.ts @@ -1,7 +1,7 @@ import { useMemo } from 'react' import { ValueRef } from '@dimensiondev/holoflows-kit' import { useValueRef } from '@masknet/shared-base-ui' -import { ProfileIdentifier } from '@masknet/shared-base' +import { EMPTY_LIST, ProfileIdentifier } from '@masknet/shared-base' import type { Profile } from '../../database' import type { SocialNetworkUI } from '../../social-network' import { activatedSocialNetworkUI, globalUIState } from '../../social-network' @@ -9,7 +9,7 @@ import { Subscription, useSubscription } from 'use-subscription' export function useFriendsList() { const ref = useValueRef(globalUIState.friends) - return useMemo(() => [...ref.values()], [ref]) + return useMemo(() => (ref.values.length ? [...ref.values()] : EMPTY_LIST), [ref]) } const default_ = new ValueRef({ identifier: ProfileIdentifier.unknown }) diff --git a/packages/mask/src/components/InjectedComponents/ProfileTabContent.tsx b/packages/mask/src/components/InjectedComponents/ProfileTabContent.tsx index c54ef4ea9e50..53966a9a2460 100644 --- a/packages/mask/src/components/InjectedComponents/ProfileTabContent.tsx +++ b/packages/mask/src/components/InjectedComponents/ProfileTabContent.tsx @@ -1,7 +1,7 @@ import { useEffect, useMemo, useState } from 'react' import { useUpdateEffect } from 'react-use' import { first } from 'lodash-unified' -import type { NextIDPlatform } from '@masknet/shared-base' +import { NextIDPlatform, EMPTY_LIST } from '@masknet/shared-base' import { Box, CircularProgress } from '@mui/material' import { makeStyles, useStylesExtends } from '@masknet/theme' import { useAddressNames } from '@masknet/web3-shared-evm' @@ -12,7 +12,6 @@ import { useCurrentVisitingIdentity, useLastRecognizedIdentity } from '../DataSo import { useNextIDBoundByPlatform } from '../DataSource/useNextID' import { usePersonaConnectStatus } from '../DataSource/usePersonaConnectStatus' import { activatedSocialNetworkUI } from '../../social-network' -import { EMPTY_LIST } from '../../../utils-pure' function getTabContent(tabId: string) { return createInjectHooksRenderer(useActivatedPluginsSNSAdaptor.visibility.useAnyMode, (x) => { diff --git a/packages/mask/src/plugins/Collectible/SNSAdaptor/Collectible.tsx b/packages/mask/src/plugins/Collectible/SNSAdaptor/Collectible.tsx index 519e257a9d9b..cb4d5b9afac0 100644 --- a/packages/mask/src/plugins/Collectible/SNSAdaptor/Collectible.tsx +++ b/packages/mask/src/plugins/Collectible/SNSAdaptor/Collectible.tsx @@ -112,10 +112,10 @@ const useStyles = makeStyles()((theme) => { padding: theme.spacing(8, 0), }, markdown: { - 'text-overflow': 'ellipsis', + textOverflow: 'ellipsis', display: '-webkit-box', - '-webkit-box-orient': 'vertical', - '-webkit-line-clamp': '3', + webkitBoxOrient: 'vertical', + webkitLineClamp: '3', }, } }) diff --git a/packages/mask/src/plugins/Collectible/hooks/useAssetOrder.ts b/packages/mask/src/plugins/Collectible/hooks/useAssetOrder.ts index ae211e1ea6cd..068223e11a47 100644 --- a/packages/mask/src/plugins/Collectible/hooks/useAssetOrder.ts +++ b/packages/mask/src/plugins/Collectible/hooks/useAssetOrder.ts @@ -10,7 +10,7 @@ import type { AssetOrder, CollectibleToken } from '../types' export function useAssetOrder(provider: NonFungibleAssetProvider, token?: CollectibleToken) { return useAsyncRetry(async () => { - if (!token) return + if (!token?.contractAddress || !token?.tokenId) return switch (provider) { case NonFungibleAssetProvider.OPENSEA: const openSeaResponse = await PluginCollectibleRPC.getAssetFromSDK(token.contractAddress, token.tokenId) @@ -37,5 +37,5 @@ export function useAssetOrder(provider: NonFungibleAssetProvider, token?: Collec default: unreachable(provider) } - }, [provider, token]) + }, [provider, token?.contractAddress, token?.tokenId]) } diff --git a/packages/mask/src/plugins/NextID/SNSAdaptor/index.tsx b/packages/mask/src/plugins/NextID/SNSAdaptor/index.tsx index 0df313132cef..139ece72debe 100644 --- a/packages/mask/src/plugins/NextID/SNSAdaptor/index.tsx +++ b/packages/mask/src/plugins/NextID/SNSAdaptor/index.tsx @@ -1,11 +1,11 @@ import type { Plugin } from '@masknet/plugin-infra' +import { EMPTY_LIST } from '@masknet/shared-base' import { base } from '../base' import { PLUGIN_ID } from '../constants' import { NextIdPage } from '../components/NextIdPage' import { RootContext } from '../contexts' import { PostTipButton, TipTaskManager } from '../components/Tip' import { Flags } from '../../../../shared' -import { EMPTY_LIST } from '@masknet/web3-shared-evm' const sns: Plugin.SNSAdaptor.Definition = { ...base, diff --git a/packages/mask/src/plugins/NextID/components/Tip/TipButton.tsx b/packages/mask/src/plugins/NextID/components/Tip/TipButton.tsx index 95cd6efcfe66..fa107279382e 100644 --- a/packages/mask/src/plugins/NextID/components/Tip/TipButton.tsx +++ b/packages/mask/src/plugins/NextID/components/Tip/TipButton.tsx @@ -1,19 +1,18 @@ import { TipCoin } from '@masknet/icons' import { usePostInfoDetails } from '@masknet/plugin-infra' -import { NextIDPlatform, ProfileIdentifier } from '@masknet/shared-base' +import { EMPTY_LIST, NextIDPlatform, ProfileIdentifier } from '@masknet/shared-base' import { makeStyles, ShadowRootTooltip } from '@masknet/theme' import { NextIDProof } from '@masknet/web3-providers' -import { EMPTY_LIST } from '@masknet/web3-shared-evm' import type { TooltipProps } from '@mui/material' import classnames from 'classnames' import { uniq } from 'lodash-unified' import { FC, HTMLProps, MouseEventHandler, useCallback, useEffect, useMemo } from 'react' import { useAsync, useAsyncFn, useAsyncRetry } from 'react-use' +import { MaskMessages } from '../../../../../shared' import Services from '../../../../extension/service' import { activatedSocialNetworkUI } from '../../../../social-network' import { useI18N } from '../../locales' import { PluginNextIdMessages } from '../../messages' -import { MaskMessages } from '../../../../../shared' interface Props extends HTMLProps { addresses?: string[] diff --git a/packages/mask/src/plugins/NextID/components/Tip/TipDialog.tsx b/packages/mask/src/plugins/NextID/components/Tip/TipDialog.tsx index 381beda5be2c..eaa9f4faebeb 100644 --- a/packages/mask/src/plugins/NextID/components/Tip/TipDialog.tsx +++ b/packages/mask/src/plugins/NextID/components/Tip/TipDialog.tsx @@ -2,8 +2,9 @@ import { SuccessIcon } from '@masknet/icons' import { PluginId, useActivatedPlugin, useCurrentWeb3NetworkPluginID } from '@masknet/plugin-infra' import { NFTCardStyledAssetPlayer } from '@masknet/shared' import { openWindow } from '@masknet/shared-base-ui' +import { EMPTY_LIST } from '@masknet/shared-base' import { makeStyles } from '@masknet/theme' -import { EMPTY_LIST, TransactionStateType, useChainId, useERC721TokenDetailed } from '@masknet/web3-shared-evm' +import { TransactionStateType, useChainId, useERC721TokenDetailed } from '@masknet/web3-shared-evm' import { DialogContent, Typography } from '@mui/material' import { useCallback, useEffect, useMemo } from 'react' import { useBoolean } from 'react-use' diff --git a/packages/mask/src/plugins/NextID/components/Tip/TipTaskManager.tsx b/packages/mask/src/plugins/NextID/components/Tip/TipTaskManager.tsx index 92dd165d32c4..0f1cff3df855 100644 --- a/packages/mask/src/plugins/NextID/components/Tip/TipTaskManager.tsx +++ b/packages/mask/src/plugins/NextID/components/Tip/TipTaskManager.tsx @@ -1,5 +1,5 @@ -import { EMPTY_LIST } from '@masknet/web3-shared-evm' import { FC, useCallback, useEffect, useState } from 'react' +import { EMPTY_LIST } from '@masknet/shared-base' import { TipTaskProvider } from '../../contexts' import { PluginNextIdMessages } from '../../messages' import type { TipTask } from '../../types' diff --git a/packages/mask/src/plugins/Savings/SNSAdaptor/SavingsDialog.tsx b/packages/mask/src/plugins/Savings/SNSAdaptor/SavingsDialog.tsx index 0a521b51376a..5c58a480a562 100644 --- a/packages/mask/src/plugins/Savings/SNSAdaptor/SavingsDialog.tsx +++ b/packages/mask/src/plugins/Savings/SNSAdaptor/SavingsDialog.tsx @@ -2,9 +2,8 @@ import { useState, useMemo } from 'react' import { useAsync } from 'react-use' import { Typography, DialogContent } from '@mui/material' import { ChainId, getChainIdFromNetworkType, useChainId } from '@masknet/web3-shared-evm' -import { isDashboardPage } from '@masknet/shared-base' +import { isDashboardPage, EMPTY_LIST } from '@masknet/shared-base' import { useI18N } from '../../../utils' -import { EMPTY_LIST } from '../../../../utils-pure' import { InjectedDialog } from '../../../components/shared/InjectedDialog' import { WalletStatusBox } from '../../../components/shared/WalletStatusBox' import { AllProviderTradeContext } from '../../Trader/trader/useAllProviderTradeContext' diff --git a/packages/mask/src/plugins/Trader/trader/uniswap/usePairs.ts b/packages/mask/src/plugins/Trader/trader/uniswap/usePairs.ts index 62856baff29a..3582a101dfe5 100644 --- a/packages/mask/src/plugins/Trader/trader/uniswap/usePairs.ts +++ b/packages/mask/src/plugins/Trader/trader/uniswap/usePairs.ts @@ -1,16 +1,16 @@ import { useMemo } from 'react' import { useAsyncRetry } from 'react-use' +import { numberToHex } from 'web3-utils' import { Pair } from '@uniswap/v2-sdk' import { CurrencyAmount, Token } from '@uniswap/sdk-core' +import { EMPTY_LIST } from '@masknet/shared-base' import { useMultipleContractSingleData } from '@masknet/web3-shared-evm' import { getPairAddress } from '../../helpers' import { usePairContracts } from '../../contracts/uniswap/usePairContract' import type { TradeProvider } from '@masknet/public-api' import { useGetTradeContext } from '../useGetTradeContext' import { TargetChainIdContext } from '../useTargetChainIdContext' -import { numberToHex } from 'web3-utils' import { useTargetBlockNumber } from '../useTargetBlockNumber' -import { EMPTY_LIST } from '../../../../../utils-pure' export enum PairState { NOT_EXISTS = 0, diff --git a/packages/mask/src/plugins/Trader/trader/useAllTradeComputed.ts b/packages/mask/src/plugins/Trader/trader/useAllTradeComputed.ts index 0479fdd0dd1e..e8f998637286 100644 --- a/packages/mask/src/plugins/Trader/trader/useAllTradeComputed.ts +++ b/packages/mask/src/plugins/Trader/trader/useAllTradeComputed.ts @@ -1,4 +1,5 @@ -import { EMPTY_LIST, FungibleTokenDetailed } from '@masknet/web3-shared-evm' +import { EMPTY_LIST } from '@masknet/shared-base' +import type { FungibleTokenDetailed } from '@masknet/web3-shared-evm' import { multipliedBy, pow10 } from '@masknet/web3-shared-base' import { useTrade as useNativeTokenTrade } from './native/useTrade' import { useTradeComputed as useNativeTokenTradeComputed } from './native/useTradeComputed' diff --git a/packages/mask/src/social-network/utils/create-post-context.ts b/packages/mask/src/social-network/utils/create-post-context.ts index 8e6561790e5f..ed34f3e81432 100644 --- a/packages/mask/src/social-network/utils/create-post-context.ts +++ b/packages/mask/src/social-network/utils/create-post-context.ts @@ -18,6 +18,7 @@ import { SubscriptionFromValueRef, SubscriptionDebug as debug, mapSubscription, + EMPTY_LIST, } from '@masknet/shared-base' import { Err, Result } from 'ts-results' import type { Subscription } from 'use-subscription' @@ -60,7 +61,7 @@ export function createSNSAdaptorSpecializedPostContext(create: PostContextSNSAct }), ) const linksSubscribe: Subscription = debug({ - getCurrentValue: () => [...links], + getCurrentValue: () => (links.size ? [...links] : EMPTY_LIST), subscribe: (sub) => links.event.on(ALL_EVENTS, sub), }) // #endregion @@ -138,7 +139,7 @@ export function createSNSAdaptorSpecializedPostContext(create: PostContextSNSAct postMetadataImages: opt.postImagesProvider || debug({ - getCurrentValue: () => [], + getCurrentValue: () => EMPTY_LIST, subscribe: () => () => {}, }), @@ -181,11 +182,12 @@ export function createRefsForCreatePostContext() { snsID: SubscriptionFromValueRef(postID), rawMessage: SubscriptionFromValueRef(postMessage), postImagesProvider: debug({ - getCurrentValue: () => [...postMetadataImages], + getCurrentValue: () => (postMetadataImages.size ? [...postMetadataImages] : EMPTY_LIST), subscribe: (sub) => postMetadataImages.event.on(ALL_EVENTS, sub), }), postMentionedLinksProvider: debug({ - getCurrentValue: () => [...postMetadataMentionedLinks.values()], + getCurrentValue: () => + postMetadataMentionedLinks.size ? [...postMetadataMentionedLinks.values()] : EMPTY_LIST, subscribe: (sub) => postMetadataMentionedLinks.event.on(ALL_EVENTS, sub), }), } diff --git a/packages/mask/utils-pure/index.ts b/packages/mask/utils-pure/index.ts index 6ba5881a1d04..3a1a43716896 100644 --- a/packages/mask/utils-pure/index.ts +++ b/packages/mask/utils-pure/index.ts @@ -1,5 +1,4 @@ export * from './type' -export * from './misc' export * from './hmr' export * from './crypto' export * from './OnDemandWorker' diff --git a/packages/plugins/RSS3/src/SNSAdaptor/TabCard.tsx b/packages/plugins/RSS3/src/SNSAdaptor/TabCard.tsx index ff077de38a14..872ef9548c42 100644 --- a/packages/plugins/RSS3/src/SNSAdaptor/TabCard.tsx +++ b/packages/plugins/RSS3/src/SNSAdaptor/TabCard.tsx @@ -1,5 +1,6 @@ import { AddressViewer } from '@masknet/shared' -import { AddressName, AddressNameType, EMPTY_LIST } from '@masknet/web3-shared-evm' +import { EMPTY_LIST } from '@masknet/shared-base' +import { AddressName, AddressNameType } from '@masknet/web3-shared-evm' import { Box, Typography } from '@mui/material' import { useI18N } from '../locales' import { useDonations, useFootprints } from './hooks' diff --git a/packages/plugins/RSS3/src/SNSAdaptor/hooks/useDonations.ts b/packages/plugins/RSS3/src/SNSAdaptor/hooks/useDonations.ts index 39c286bd6628..faecb82d8c85 100644 --- a/packages/plugins/RSS3/src/SNSAdaptor/hooks/useDonations.ts +++ b/packages/plugins/RSS3/src/SNSAdaptor/hooks/useDonations.ts @@ -1,5 +1,5 @@ -import { EMPTY_LIST } from '@masknet/web3-shared-evm' import { useAsync } from 'react-use' +import { EMPTY_LIST } from '@masknet/shared-base' import { PluginProfileRPC } from '../../messages' export function useDonations(address: string) { diff --git a/packages/polyfills/types/env.d.ts b/packages/polyfills/types/env.d.ts index fdfb80edad90..fd62cb5a743f 100644 --- a/packages/polyfills/types/env.d.ts +++ b/packages/polyfills/types/env.d.ts @@ -4,6 +4,7 @@ declare namespace NodeJS { } interface ProcessEnv { readonly NODE_ENV: 'production' | 'development' + readonly architecture: 'app' | 'web' } } declare var process: NodeJS.Process diff --git a/packages/public-api/src/web.ts b/packages/public-api/src/web.ts index 4dad3ec0778a..eaebe68c57c3 100644 --- a/packages/public-api/src/web.ts +++ b/packages/public-api/src/web.ts @@ -177,24 +177,6 @@ export enum LaunchPage { dashboard = 'dashboard', } -// This type MUST be sync with NetworkType in packages/web3-shared/src/types/index.ts -export enum NetworkType { - Ethereum = 'Ethereum', - Binance = 'Binance', - Polygon = 'Polygon', - Arbitrum = 'Arbitrum', - xDai = 'xDai', - Celo = 'Celo', - Fantom = 'Fantom', - Aurora = 'Aurora', - Avalanche = 'Avalanche', - Boba = 'Boba', - Fuse = 'Fuse', - Metis = 'Metis', - Optimistic = 'Optimistic', - Conflux = 'Conflux', -} - export enum DataProvider { COIN_GECKO = 0, COIN_MARKET_CAP = 1, @@ -219,6 +201,7 @@ export enum TradeProvider { PANGOLIN = 14, MDEX = 15, } + /** Supported language settings */ export enum LanguageOptions { __auto__ = 'auto', @@ -237,3 +220,55 @@ export enum SupportedLanguages { koKR = 'ko-KR', jaJP = 'ja-JP', } + +/** + * Keep updating to packages/web3-shared/evm/types/index.ts + */ +export enum NetworkType { + Ethereum = 'Ethereum', + Binance = 'Binance', + Polygon = 'Polygon', + Arbitrum = 'Arbitrum', + xDai = 'xDai', + Celo = 'Celo', + Fantom = 'Fantom', + Aurora = 'Aurora', + Avalanche = 'Avalanche', + Boba = 'Boba', + Fuse = 'Fuse', + Metis = 'Metis', + Optimistic = 'Optimistic', + Conflux = 'Conflux', +} + +export enum ProviderType { + MaskWallet = 'Maskbook', + MetaMask = 'MetaMask', + WalletConnect = 'WalletConnect', + Fortmatic = 'Fortmatic', + Coin98 = 'Coin98', + MathWallet = 'MathWallet', + WalletLink = 'WalletLink', + CustomNetwork = 'CustomNetwork', +} + +export enum FungibleAssetProvider { + ZERION = 'Zerion', + DEBANK = 'Debank', +} + +export enum NonFungibleAssetProvider { + OPENSEA = 'OpenSea', + RARIBLE = 'Rarible', + NFTSCAN = 'NFTScan', + ZORA = 'Zora', +} + +export interface PriceRecord { + [currency: string]: number +} + +/** Base on response of coingecko's token price API */ +export interface CryptoPrice { + [token: string]: PriceRecord +} diff --git a/packages/shared-base/package.json b/packages/shared-base/package.json index 258140585c98..aad758c4315c 100644 --- a/packages/shared-base/package.json +++ b/packages/shared-base/package.json @@ -7,6 +7,7 @@ "dependencies": { "@dimensiondev/holoflows-kit": "^0.9.0-20210902104757-7c3d0d0", "@masknet/typed-message": "workspace:*", + "@masknet/public-api": "workspace:*", "@msgpack/msgpack": "^2.7.2", "@mui/icons-material": "link:..\\empty", "@mui/lab": "link:..\\empty", diff --git a/packages/shared-base/src/Messages/Mask.ts b/packages/shared-base/src/Messages/Mask.ts index 8d158b800a07..cd28c9012b96 100644 --- a/packages/shared-base/src/Messages/Mask.ts +++ b/packages/shared-base/src/Messages/Mask.ts @@ -1,14 +1,16 @@ -import type { SerializableTypedMessages } from '@masknet/typed-message' -import type { ProfileIdentifier, PersonaIdentifier } from '../Identifier/type' -import type { RelationFavor } from '../Persona/type' -import type { Appearance, LanguageOptions, DataProvider } from '../../../public-api/src/web' import type { + Appearance, + LanguageOptions, + DataProvider, CryptoPrice, NetworkType, ProviderType, FungibleAssetProvider, NonFungibleAssetProvider, -} from '../../../web3-shared/evm' +} from '@masknet/public-api' +import type { SerializableTypedMessages } from '@masknet/typed-message' +import type { ProfileIdentifier, PersonaIdentifier } from '../Identifier/type' +import type { RelationFavor } from '../Persona/type' export interface MaskSettingsEvents { appearanceSettings: Appearance diff --git a/packages/mask/utils-pure/misc.ts b/packages/shared-base/src/Pure/index.ts similarity index 100% rename from packages/mask/utils-pure/misc.ts rename to packages/shared-base/src/Pure/index.ts diff --git a/packages/shared-base/src/index.ts b/packages/shared-base/src/index.ts index 56e35ef4537e..4a484473aba0 100644 --- a/packages/shared-base/src/index.ts +++ b/packages/shared-base/src/index.ts @@ -7,6 +7,7 @@ export * from './i18n' export * from './utils' export * from './kv-storage' export * from './crypto' +export * from './Pure' export * from './Persona/type' export * from './Post/type' export * from './Persona/type' diff --git a/packages/shared-base/tsconfig.json b/packages/shared-base/tsconfig.json index 398b55ddd11e..21eef249d5b7 100644 --- a/packages/shared-base/tsconfig.json +++ b/packages/shared-base/tsconfig.json @@ -7,5 +7,5 @@ }, "include": ["./src", "./src/**/*.json"], // Only type-level dependency. - "references": [{ "path": "../public-api" }, { "path": "../web3-shared/evm" }, { "path": "../typed-message/base" }] + "references": [{ "path": "../public-api" }, { "path": "../typed-message/base" }] } diff --git a/packages/theme/package.json b/packages/theme/package.json index a924008c6ee2..d0828f1839d8 100644 --- a/packages/theme/package.json +++ b/packages/theme/package.json @@ -22,6 +22,7 @@ }, "dependencies": { "@masknet/icons": "workspace:*", + "@masknet/shared-base": "workspace:*", "@masknet/storybook-shared": "workspace:*", "@types/qrcode": "^1.4.2", "@types/tinycolor2": "^1.4.3", diff --git a/packages/theme/src/ShadowRoot/createReactRootShadowed.tsx b/packages/theme/src/ShadowRoot/createReactRootShadowed.tsx index a76abe77a4f2..583c98b523f4 100644 --- a/packages/theme/src/ShadowRoot/createReactRootShadowed.tsx +++ b/packages/theme/src/ShadowRoot/createReactRootShadowed.tsx @@ -1,5 +1,6 @@ import { StrictMode } from 'react' import { createRoot } from 'react-dom/client' +import { noop } from 'lodash-unified' import type {} from 'react/next' import type {} from 'react-dom/next' import { ShadowRootStyleProvider } from './ShadowRootStyleProvider' @@ -68,8 +69,8 @@ function mount( if (shadow.querySelector(`${tag}.${key}`)) { console.error('Tried to create root in', shadow, 'with key', key, ' which is already used. Skip rendering.') return { - destory: () => {}, - render: () => {}, + destory: noop, + render: noop, } } diff --git a/packages/theme/tsconfig.json b/packages/theme/tsconfig.json index bb4139031a1a..174fe5764c22 100644 --- a/packages/theme/tsconfig.json +++ b/packages/theme/tsconfig.json @@ -6,5 +6,5 @@ "tsBuildInfoFile": "./dist/src.tsbuildinfo" }, "include": ["./src"], - "references": [{ "path": "../icons" }] + "references": [{ "path": "../icons" }, { "path": "../shared-base" }] } diff --git a/packages/web3-shared/base/src/utils/number.ts b/packages/web3-shared/base/src/utils/number.ts index 042a5b0b6deb..b061820adf29 100644 --- a/packages/web3-shared/base/src/utils/number.ts +++ b/packages/web3-shared/base/src/utils/number.ts @@ -44,6 +44,7 @@ export function multipliedBy(a: BigNumber.Value, b: BigNumber.Value) { } /** 10 ** n */ +/** @deprecated use scale10 */ export function pow10(n: BigNumber.Value) { return new BigNumber(10).pow(n) } diff --git a/packages/web3-shared/evm/hooks/useAssets.ts b/packages/web3-shared/evm/hooks/useAssets.ts index 9ca15511ba4b..d90a63d611a2 100644 --- a/packages/web3-shared/evm/hooks/useAssets.ts +++ b/packages/web3-shared/evm/hooks/useAssets.ts @@ -1,3 +1,4 @@ +import { EMPTY_LIST } from '@masknet/shared-base' import type { ChainId, FungibleTokenDetailed } from '../types' import { useWallet } from './useWallet' import { useNativeTokenDetailed } from './useNativeTokenDetailed' @@ -5,7 +6,7 @@ import { useAssetsFromChain } from './useAssetsFromChain' import { useAssetsFromProvider } from './useAssetsFromProvider' import { useCallback, useMemo } from 'react' import { useAssetsMerged } from './useAssetsMerged' -import { formatEthereumAddress, EMPTY_LIST } from '../utils' +import { formatEthereumAddress } from '../utils' export function useAssets(tokens: FungibleTokenDetailed[], chainId?: ChainId | 'all') { const wallet = useWallet() diff --git a/packages/web3-shared/evm/hooks/useAssetsFromChain.ts b/packages/web3-shared/evm/hooks/useAssetsFromChain.ts index 28d0a326453b..ac4cb59a1cde 100644 --- a/packages/web3-shared/evm/hooks/useAssetsFromChain.ts +++ b/packages/web3-shared/evm/hooks/useAssetsFromChain.ts @@ -1,9 +1,10 @@ import { useMemo } from 'react' import { first } from 'lodash-unified' +import { EMPTY_LIST } from '@masknet/shared-base' import { Asset, ChainId, EthereumTokenType, FungibleTokenDetailed } from '../types' import { useTokensBalance } from './useTokensBalance' import { useChainDetailed } from './useChainDetailed' -import { getChainDetailed, EMPTY_LIST } from '../utils' +import { getChainDetailed } from '../utils' import { useBalance } from './useBalance' export function useAssetsFromChain(tokens: FungibleTokenDetailed[], chainId?: ChainId) { diff --git a/packages/web3-shared/evm/hooks/useAssetsMerged.ts b/packages/web3-shared/evm/hooks/useAssetsMerged.ts index 231f8d9b6a89..36b25f1fece4 100644 --- a/packages/web3-shared/evm/hooks/useAssetsMerged.ts +++ b/packages/web3-shared/evm/hooks/useAssetsMerged.ts @@ -1,8 +1,9 @@ -import { uniqBy } from 'lodash-unified' import { useMemo } from 'react' +import { uniqBy } from 'lodash-unified' +import { EMPTY_LIST } from '@masknet/shared-base' import { useTokenConstants } from '../constants' import type { Asset } from '../types' -import { formatEthereumAddress, makeSortAssertFn, EMPTY_LIST } from '../utils' +import { formatEthereumAddress, makeSortAssertFn } from '../utils' import { useChainId } from './useChainId' /** diff --git a/packages/web3-shared/evm/hooks/useTokensBalance.ts b/packages/web3-shared/evm/hooks/useTokensBalance.ts index f5c0f5d2a272..263b47242aac 100644 --- a/packages/web3-shared/evm/hooks/useTokensBalance.ts +++ b/packages/web3-shared/evm/hooks/useTokensBalance.ts @@ -1,10 +1,10 @@ import { useAsyncRetry } from 'react-use' +import { numberToHex } from 'web3-utils' +import { EMPTY_LIST } from '@masknet/shared-base' import { useBalanceCheckerContract } from '../contracts/useBalanceChecker' import { useAccount } from './useAccount' import { useChainId } from './useChainId' import type { ChainId } from '../types' -import { EMPTY_LIST } from '../utils' -import { numberToHex } from 'web3-utils' /** * Fetch balance of multiple tokens from chain diff --git a/packages/web3-shared/evm/tsconfig.json b/packages/web3-shared/evm/tsconfig.json index 31e14ea11894..209fa3f77a5f 100644 --- a/packages/web3-shared/evm/tsconfig.json +++ b/packages/web3-shared/evm/tsconfig.json @@ -6,5 +6,5 @@ "tsBuildInfoFile": "../dist/evm.tsbuildinfo" }, "include": ["./", "./**/*.json"], - "references": [{ "path": "../../injected-script/sdk" }, { "path": "../base" }] + "references": [{ "path": "../base" }, { "path": "../../shared-base" }, { "path": "../../injected-script/sdk" }] } diff --git a/packages/web3-shared/evm/types/index.ts b/packages/web3-shared/evm/types/index.ts index 18588cb9e6d5..279218585455 100644 --- a/packages/web3-shared/evm/types/index.ts +++ b/packages/web3-shared/evm/types/index.ts @@ -15,14 +15,6 @@ export enum CurrencyType { USD = 'usd', } -export interface PriceRecord { - [currency: string]: number -} - -/** Base on response of coingecko's token price API */ -export interface CryptoPrice { - [token: string]: PriceRecord -} export type ChainIdOptionalRecord = { [k in ChainId]?: T } export type ChainIdRecord = { [k in ChainId]: T } @@ -83,42 +75,12 @@ export enum ChainId { Conflux = 1030, } -export enum ProviderType { - MaskWallet = 'Maskbook', - MetaMask = 'MetaMask', - WalletConnect = 'WalletConnect', - Fortmatic = 'Fortmatic', - Coin98 = 'Coin98', - MathWallet = 'MathWallet', - WalletLink = 'WalletLink', - CustomNetwork = 'CustomNetwork', -} - export enum LockStatus { INIT = 0, UNLOCK = 1, LOCKED = 2, } -// If you change this enum, please sync it to packages/public-api/src/web.ts -// (it's a breaking change. Please notify the iOS and Android dev) -export enum NetworkType { - Ethereum = 'Ethereum', - Binance = 'Binance', - Polygon = 'Polygon', - Arbitrum = 'Arbitrum', - xDai = 'xDai', - Celo = 'Celo', - Fantom = 'Fantom', - Aurora = 'Aurora', - Avalanche = 'Avalanche', - Boba = 'Boba', - Fuse = 'Fuse', - Metis = 'Metis', - Optimistic = 'Optimistic', - Conflux = 'Conflux', -} - export interface Wallet { /** User define wallet name. Default address.prefix(6) */ name: string @@ -579,18 +541,6 @@ export enum DomainProvider { UNS = 'UNS', } -export enum FungibleAssetProvider { - ZERION = 'Zerion', - DEBANK = 'Debank', -} - -export enum NonFungibleAssetProvider { - OPENSEA = 'OpenSea', - RARIBLE = 'Rarible', - NFTSCAN = 'NFTScan', - ZORA = 'Zora', -} - export type UnboxTransactionObject = T extends NonPayableTransactionObject ? R : T extends PayableTransactionObject @@ -691,3 +641,55 @@ export enum TransactionStateType { /** Fail to send */ FAILED = 5, } + +/** + * Keep updating to packages/public-api/src/web.ts + */ +export enum NetworkType { + Ethereum = 'Ethereum', + Binance = 'Binance', + Polygon = 'Polygon', + Arbitrum = 'Arbitrum', + xDai = 'xDai', + Celo = 'Celo', + Fantom = 'Fantom', + Aurora = 'Aurora', + Avalanche = 'Avalanche', + Boba = 'Boba', + Fuse = 'Fuse', + Metis = 'Metis', + Optimistic = 'Optimistic', + Conflux = 'Conflux', +} + +export enum ProviderType { + MaskWallet = 'Maskbook', + MetaMask = 'MetaMask', + WalletConnect = 'WalletConnect', + Fortmatic = 'Fortmatic', + Coin98 = 'Coin98', + MathWallet = 'MathWallet', + WalletLink = 'WalletLink', + CustomNetwork = 'CustomNetwork', +} + +export enum FungibleAssetProvider { + ZERION = 'Zerion', + DEBANK = 'Debank', +} + +export enum NonFungibleAssetProvider { + OPENSEA = 'OpenSea', + RARIBLE = 'Rarible', + NFTSCAN = 'NFTScan', + ZORA = 'Zora', +} + +export interface PriceRecord { + [currency: string]: number +} + +/** Base on response of coingecko's token price API */ +export interface CryptoPrice { + [token: string]: PriceRecord +} diff --git a/packages/web3-shared/evm/utils/address.ts b/packages/web3-shared/evm/utils/address.ts index 6cec9e201dfe..2bb6247e301e 100644 --- a/packages/web3-shared/evm/utils/address.ts +++ b/packages/web3-shared/evm/utils/address.ts @@ -1,6 +1,6 @@ -import { getEnumAsArray } from '@dimensiondev/kit' -import { compact, castArray, uniq } from 'lodash-unified' import { EthereumAddress } from 'wallet.ts' +import { compact, castArray, uniq } from 'lodash-unified' +import { getEnumAsArray } from '@dimensiondev/kit' import { getRedPacketConstants, getTokenConstants, ZERO_ADDRESS } from '../constants' import { ChainId } from '../types' diff --git a/packages/web3-shared/evm/utils/index.ts b/packages/web3-shared/evm/utils/index.ts index 5d5011871555..a74ca021754b 100644 --- a/packages/web3-shared/evm/utils/index.ts +++ b/packages/web3-shared/evm/utils/index.ts @@ -7,5 +7,4 @@ export * from './chainDetailed' export * from './transaction' export * from './domain' export * from './payload' -export * from './misc' export * from './provider' diff --git a/packages/web3-shared/flow/tsconfig.json b/packages/web3-shared/flow/tsconfig.json index b5b903e4be17..10de013f5120 100644 --- a/packages/web3-shared/flow/tsconfig.json +++ b/packages/web3-shared/flow/tsconfig.json @@ -6,5 +6,5 @@ "tsBuildInfoFile": "../dist/flow.tsbuildinfo" }, "include": ["./", "./**/*.json"], - "references": [{ "path": "../../web3-shared/base" }] + "references": [{ "path": "../base" }] } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ce04eb270ac0..58c7fde01215 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1036,6 +1036,7 @@ importers: packages/shared-base: specifiers: '@dimensiondev/holoflows-kit': ^0.9.0-20210902104757-7c3d0d0 + '@masknet/public-api': workspace:* '@masknet/typed-message': workspace:* '@msgpack/msgpack': ^2.7.2 '@mui/icons-material': link:..\empty @@ -1058,6 +1059,7 @@ importers: z-schema: ^5.0.2 dependencies: '@dimensiondev/holoflows-kit': 0.9.0-20210902104757-7c3d0d0 + '@masknet/public-api': link:../public-api '@masknet/typed-message': link:../typed-message '@msgpack/msgpack': 2.7.2 '@mui/icons-material': link:../empty @@ -1108,6 +1110,7 @@ importers: specifiers: '@babel/core': ^7.17.8 '@masknet/icons': workspace:* + '@masknet/shared-base': workspace:* '@masknet/storybook-shared': workspace:* '@storybook/addon-actions': ^6.4.19 '@storybook/addon-essentials': ^6.4.19 @@ -1128,6 +1131,7 @@ importers: use-subscription: ^1.5.1 dependencies: '@masknet/icons': link:../icons + '@masknet/shared-base': link:../shared-base '@masknet/storybook-shared': link:../storybook-shared '@types/qrcode': 1.4.2 '@types/tinycolor2': 1.4.3 From 0b4bb2851df9e988c2deaae5f6b58a5016d779e0 Mon Sep 17 00:00:00 2001 From: UncleBill Date: Thu, 31 Mar 2022 16:44:53 +0800 Subject: [PATCH 27/42] refactor: turn token picking into async call (#5632) * refactor: refactor token picking into async call * fix: try to fix build * refactor: introduce runtime * refactor: move injectedDialog into ui-runtime * fix: wrap only once * fix: rename runtimes to runtime * fix: SelectTokenDialog * Update packages/runtime/ui/README.md Co-authored-by: guanbinrui <52657989+guanbinrui@users.noreply.github.com> * fix: import defer from dimensiondev/kit * fix: i18n * fix: wrap inside CustomSnackbarProvider * fix: move into packages/shared * fix: reactive networkIdentifier and componentOverwrite * fix: follow up comments Co-authored-by: guanbinrui <52657989+guanbinrui@users.noreply.github.com> --- package.json | 2 +- packages/dashboard/package.json | 1 + .../src/initialization/Dashboard.tsx | 12 +- .../pages/Wallets/components/Assets/index.tsx | 48 +++---- .../components/Transfer/TransferERC20.tsx | 61 ++++----- .../components/Transfer/TransferERC721.tsx | 2 +- packages/dashboard/tsconfig.json | 1 + packages/mask/shared-ui/locales/en-US.json | 1 - packages/mask/shared-ui/locales/ja-JP.json | 1 - packages/mask/shared-ui/locales/ko-KR.json | 1 - packages/mask/shared-ui/locales/qya-AA.json | 1 - packages/mask/shared-ui/locales/zh-CN.json | 1 - packages/mask/shared-ui/locales/zh-TW.json | 1 - packages/mask/src/UIRoot.tsx | 3 +- .../CompositionDialog/Composition.tsx | 2 +- .../InjectedComponents/CommentBox.tsx | 6 +- .../InjectedComponents/SelectPeopleDialog.tsx | 2 +- .../shared/DebugMetadataInspector.tsx | 2 +- .../SelectRecipientsDialog.tsx | 10 +- .../src/extension/popups/pages/Swap/index.tsx | 49 +++---- .../ArtBlocks/SNSAdaptor/PurchaseDialog.tsx | 9 +- .../src/plugins/Avatar/SNSAdaptor/AddNFT.tsx | 2 +- .../Collectible/SNSAdaptor/CheckoutDialog.tsx | 2 +- .../SNSAdaptor/MakeOfferDialog.tsx | 2 +- .../SNSAdaptor/PostListingDialog.tsx | 2 +- .../CryptoartAI/SNSAdaptor/CheckoutDialog.tsx | 4 +- .../SNSAdaptor/MakeOfferDialog.tsx | 4 +- packages/mask/src/plugins/EVM/messages.ts | 4 +- .../External/components/CompositionEntry.tsx | 2 +- .../SNSAdaptor/FindTrumanDialog.tsx | 2 +- .../FindTruman/SNSAdaptor/MainDialog.tsx | 2 +- .../SNSAdaptor/ParticipatePanel.tsx | 2 +- .../FindTruman/SNSAdaptor/PartsPanel.tsx | 2 +- .../Gitcoin/SNSAdaptor/DonateDialog.tsx | 40 ++---- .../GoodGhosting/UI/GameActionDialog.tsx | 2 +- .../plugins/ITO/SNSAdaptor/ClaimAllDialog.tsx | 3 +- .../ITO/SNSAdaptor/CompositionDialog.tsx | 3 +- .../ITO/SNSAdaptor/ExchangeTokenPanel.tsx | 42 +++--- .../plugins/ITO/SNSAdaptor/RegionSelect.tsx | 4 +- .../ITO/SNSAdaptor/SelectTokenAmountPanel.tsx | 30 ++--- .../src/plugins/ITO/SNSAdaptor/SwapDialog.tsx | 81 +++++------ .../src/plugins/ITO/SNSAdaptor/SwapGuide.tsx | 2 +- .../plugins/ITO/SNSAdaptor/UnlockDialog.tsx | 44 ++---- .../SNSAdaptor/components/DrawDialog.tsx | 3 +- .../components/DrawResultDialog.tsx | 2 +- .../plugins/NextID/components/BindPanelUI.tsx | 5 +- .../NextID/components/ConfirmModal.tsx | 2 +- .../NextID/components/Tip/TipDialog.tsx | 5 +- .../plugins/NextID/components/Tip/TipForm.tsx | 33 ++--- .../NextID/components/UnbindPanelUI.tsx | 5 +- .../src/plugins/Pets/SNSAdaptor/PetDialog.tsx | 2 +- .../plugins/Polls/SNSAdaptor/PollsDialog.tsx | 2 +- .../plugins/PoolTogether/UI/DepositDialog.tsx | 42 ++---- .../SNSAdaptor/RedPacketCreateNew.tsx | 2 +- .../RedPacket/SNSAdaptor/RedPacketDialog.tsx | 2 +- .../SNSAdaptor/RedPacketERC20Form.tsx | 41 ++---- .../SNSAdaptor/RedPacketNftShare.tsx | 2 +- .../SNSAdaptor/RedpacketNftConfirmDialog.tsx | 3 +- .../SNSAdaptor/SelectNftTokenDialog.tsx | 3 +- .../Savings/SNSAdaptor/SavingsDialog.tsx | 2 +- .../Snapshot/SNSAdaptor/VoteConfirmDialog.tsx | 2 +- .../SNSAdaptor/trader/ConfirmDialog.tsx | 5 +- .../SNSAdaptor/trader/SettingsDialog.tsx | 2 +- .../Trader/SNSAdaptor/trader/Trader.tsx | 46 ++----- .../Trader/SNSAdaptor/trader/TraderDialog.tsx | 2 +- .../SNSAdaptor/trending/CoinMetadataTags.tsx | 2 +- .../SNSAdaptor/trending/TrendingPopper.tsx | 1 - .../Transak/SNSAdaptor/BuyTokenDialog.tsx | 2 +- .../SelectRecipientsUnlockDialog.tsx | 2 +- .../SNSAdaptor/UnlockProtocolDialog.tsx | 2 +- .../src/plugins/Wallet/Dashboard/index.tsx | 3 - .../SNSAdaptor/ConnectWalletDialog/index.tsx | 2 +- .../SNSAdaptor/GasSettingDialog/index.tsx | 2 +- .../Wallet/SNSAdaptor/RenameWalletDialog.tsx | 5 +- .../RestoreLegacyWalletDialog/index.tsx | 2 +- .../SNSAdaptor/RiskWarningDialog/index.tsx | 2 +- .../SNSAdaptor/SelectNftContractDialog.tsx | 4 +- .../SNSAdaptor/SelectProviderDialog/index.tsx | 4 +- .../Wallet/SNSAdaptor/SelectTokenDialog.tsx | 126 ------------------ .../Wallet/SNSAdaptor/SelectWalletDialog.tsx | 2 +- .../Wallet/SNSAdaptor/TransactionDialog.tsx | 4 +- .../WalletConnectQRCodeDialog/index.tsx | 4 +- .../SNSAdaptor/WalletStatusDialog/index.tsx | 2 +- .../src/plugins/Wallet/SNSAdaptor/index.tsx | 2 - packages/mask/src/plugins/Wallet/messages.ts | 2 +- .../src/plugins/dHEDGE/UI/InvestDialog.tsx | 38 ++---- .../facebook.com/ui-provider.ts | 4 +- .../instagram.com/base.ts | 8 +- .../injection/NFT/NFTAvatarSettingDialog.tsx | 2 +- .../social-network-adaptor/minds.com/base.ts | 2 +- .../minds.com/ui-provider.ts | 4 +- .../social-network-adaptor/opensea.io/base.ts | 2 +- .../twitter.com/base.ts | 6 +- .../twitter.com/ui-provider.ts | 4 +- packages/mask/src/social-network/types.ts | 9 +- packages/mask/src/social-network/ui.ts | 7 + .../utils/create-post-context.ts | 2 +- packages/mask/src/tsconfig.json | 1 + packages/mask/src/utils/shadow-root/index.ts | 5 - packages/plugins/Wallet/src/messages.ts | 43 +----- packages/shared-base-ui/package.json | 6 +- .../src/hooks/useRemoteControlledDialog.ts | 2 +- packages/shared/package.json | 4 +- packages/shared/src/constants.tsx | 16 ++- .../src/contexts/SharedContextProvider.tsx | 11 ++ .../contexts/base/BaseSharedUIProvider.tsx | 36 +++++ packages/shared/src/contexts/base/index.ts | 2 + packages/shared/src/contexts/base/types.ts | 6 + .../contexts/components/DialogDismissIcon.tsx | 20 +++ .../contexts/components}/InjectedDialog.tsx | 45 +++---- .../shared/src/contexts/components/index.ts | 1 + .../evm/TokenPicker/SelectTokenDialog.tsx | 110 +++++++++++++++ .../src/contexts/evm/TokenPicker/index.tsx | 66 +++++++++ .../contexts/evm/TokenPicker/useRowSize.ts | 15 +++ packages/shared/src/contexts/evm/index.tsx | 8 ++ packages/shared/src/contexts/index.ts | 4 + packages/shared/src/index.ts | 1 + packages/shared/src/locales/en-US.json | 3 +- packages/shared/tsconfig.json | 1 + .../theme/src/Components/Snackbar/index.tsx | 2 +- packages/theme/src/customization/index.ts | 1 + packages/theme/src/customization/types.ts | 6 + packages/theme/src/index.ts | 1 + packages/web3-shared/evm/hooks/useSocket.ts | 2 +- pnpm-lock.yaml | 45 ++++--- 125 files changed, 702 insertions(+), 734 deletions(-) delete mode 100644 packages/mask/src/plugins/Wallet/SNSAdaptor/SelectTokenDialog.tsx create mode 100644 packages/shared/src/contexts/SharedContextProvider.tsx create mode 100644 packages/shared/src/contexts/base/BaseSharedUIProvider.tsx create mode 100644 packages/shared/src/contexts/base/index.ts create mode 100644 packages/shared/src/contexts/base/types.ts create mode 100644 packages/shared/src/contexts/components/DialogDismissIcon.tsx rename packages/{mask/src/components/shared => shared/src/contexts/components}/InjectedDialog.tsx (82%) create mode 100644 packages/shared/src/contexts/components/index.ts create mode 100644 packages/shared/src/contexts/evm/TokenPicker/SelectTokenDialog.tsx create mode 100644 packages/shared/src/contexts/evm/TokenPicker/index.tsx create mode 100644 packages/shared/src/contexts/evm/TokenPicker/useRowSize.ts create mode 100644 packages/shared/src/contexts/evm/index.tsx create mode 100644 packages/shared/src/contexts/index.ts create mode 100644 packages/theme/src/customization/index.ts create mode 100644 packages/theme/src/customization/types.ts diff --git a/package.json b/package.json index 30cdea4cdc89..f2702bbc5981 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,7 @@ "spellcheck": "cspell lint --no-must-find-files" }, "dependencies": { - "@dimensiondev/kit": "0.0.0-20220223101101-4e6f3b9", + "@dimensiondev/kit": "0.0.0-20220228054820-f2378be", "@emotion/cache": "^11.7.1", "@emotion/react": "^11.8.2", "@emotion/serialize": "^1.0.2", diff --git a/packages/dashboard/package.json b/packages/dashboard/package.json index ce2763edbced..c7f036f22780 100644 --- a/packages/dashboard/package.json +++ b/packages/dashboard/package.json @@ -15,6 +15,7 @@ "@masknet/icons": "workspace:*", "@masknet/plugin-example": "workspace:*", "@masknet/plugin-flow": "workspace:*", + "@masknet/plugin-solana": "workspace:*", "@masknet/plugin-infra": "workspace:*", "@masknet/plugin-wallet": "workspace:*", "@masknet/public-api": "workspace:*", diff --git a/packages/dashboard/src/initialization/Dashboard.tsx b/packages/dashboard/src/initialization/Dashboard.tsx index b8d4d7932ac1..a1f3583fc014 100644 --- a/packages/dashboard/src/initialization/Dashboard.tsx +++ b/packages/dashboard/src/initialization/Dashboard.tsx @@ -7,7 +7,7 @@ import { MaskDarkTheme, useSystemPreferencePalette, } from '@masknet/theme' -import { I18NextProviderHMR } from '@masknet/shared' +import { I18NextProviderHMR, SharedContextProvider } from '@masknet/shared' import { ErrorBoundary } from '@masknet/shared-base-ui' import { createInjectHooksRenderer, @@ -62,10 +62,12 @@ export default function DashboardRoot() { - - - - + + + + + + diff --git a/packages/dashboard/src/pages/Wallets/components/Assets/index.tsx b/packages/dashboard/src/pages/Wallets/components/Assets/index.tsx index 2bb501567f86..6a1dcba73df4 100644 --- a/packages/dashboard/src/pages/Wallets/components/Assets/index.tsx +++ b/packages/dashboard/src/pages/Wallets/components/Assets/index.tsx @@ -1,17 +1,15 @@ -import { memo, useEffect, useState } from 'react' -import { ContentContainer } from '../../../../components/ContentContainer' +import type { Web3Plugin } from '@masknet/plugin-infra' +import { NetworkPluginID, useCurrentWeb3NetworkPluginID } from '@masknet/plugin-infra' +import { makeStyles, useTabs } from '@masknet/theme' import { TabContext, TabList, TabPanel } from '@mui/lab' import { Box, Button, Tab } from '@mui/material' -import { makeStyles, useTabs } from '@masknet/theme' -import { FungibleTokenTable } from '../FungibleTokenTable' +import { memo, useEffect, useState } from 'react' +import { usePickToken } from '@masknet/shared' +import { ContentContainer } from '../../../../components/ContentContainer' import { useDashboardI18N } from '../../../../locales' -import { CollectibleList } from '../CollectibleList' import { AddCollectibleDialog } from '../AddCollectibleDialog' -import { useRemoteControlledDialog } from '@masknet/shared-base-ui' -import { PluginMessages } from '../../../../API' -import type { Web3Plugin } from '@masknet/plugin-infra' -import { NetworkPluginID, useCurrentWeb3NetworkPluginID } from '@masknet/plugin-infra' -import { v4 as uuid } from 'uuid' +import { CollectibleList } from '../CollectibleList' +import { FungibleTokenTable } from '../FungibleTokenTable' const useStyles = makeStyles()((theme) => ({ caption: { @@ -48,7 +46,6 @@ export const Assets = memo(({ network }) => { const t = useDashboardI18N() const pluginId = useCurrentWeb3NetworkPluginID() const { classes } = useStyles() - const [id] = useState(uuid()) const assetTabsLabel: Record = { [AssetTab.Token]: t.wallets_assets_token(), [AssetTab.Investment]: t.wallets_assets_investment(), @@ -58,15 +55,13 @@ export const Assets = memo(({ network }) => { const [currentTab, onChange, , setTab] = useTabs(AssetTab.Token, AssetTab.Collectibles) const [addCollectibleOpen, setAddCollectibleOpen] = useState(false) - const { setDialog: setSelectToken } = useRemoteControlledDialog( - PluginMessages.Wallet.events.selectTokenDialogUpdated, - ) useEffect(() => { setTab(AssetTab.Token) }, [pluginId]) const showCollectibles = [NetworkPluginID.PLUGIN_EVM, NetworkPluginID.PLUGIN_SOLANA].includes(pluginId) + const pickToken = usePickToken() return ( <> @@ -85,16 +80,17 @@ export const Assets = memo(({ network }) => { size="small" color="secondary" className={classes.addCustomTokenButton} - onClick={() => - currentTab === AssetTab.Token - ? setSelectToken({ - open: true, - uuid: id, - title: t.wallets_add_token(), - FungibleTokenListProps: { whitelist: [] }, - }) - : setAddCollectibleOpen(true) - }> + onClick={async () => { + if (currentTab === AssetTab.Token) { + // TODO handle result + await pickToken({ + whitelist: [], + title: t.wallets_add_token(), + }) + } else { + setAddCollectibleOpen(true) + } + }}> +{' '} {currentTab === AssetTab.Token ? t.wallets_add_token() @@ -113,9 +109,7 @@ export const Assets = memo(({ network }) => { - {addCollectibleOpen && ( - setAddCollectibleOpen(false)} /> - )} + {addCollectibleOpen && setAddCollectibleOpen(false)} />} ) }) diff --git a/packages/dashboard/src/pages/Wallets/components/Transfer/TransferERC20.tsx b/packages/dashboard/src/pages/Wallets/components/Transfer/TransferERC20.tsx index ce5f9e651744..201755ea9479 100644 --- a/packages/dashboard/src/pages/Wallets/components/Transfer/TransferERC20.tsx +++ b/packages/dashboard/src/pages/Wallets/components/Transfer/TransferERC20.tsx @@ -1,6 +1,16 @@ +import { RightIcon } from '@masknet/icons' +import { + NetworkPluginID, + TokenType, + useLookupAddress, + useNetworkDescriptor, + useWeb3State, + Web3Plugin, +} from '@masknet/plugin-infra' +import { NetworkType } from '@masknet/public-api' +import { FormattedAddress, TokenAmountPanel, usePickToken } from '@masknet/shared' import { MaskColorVar, MaskTextField } from '@masknet/theme' -import { Box, Button, IconButton, Link, Popover, Stack, Typography } from '@mui/material' -import { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react' +import { isGreaterThan, isZero, multipliedBy, rightShift } from '@masknet/web3-shared-base' import { addGasMargin, EthereumTokenType, @@ -17,29 +27,15 @@ import { useTokenConstants, useTokenTransferCallback, } from '@masknet/web3-shared-evm' -import { useRemoteControlledDialog } from '@masknet/shared-base-ui' -import { isGreaterThan, isZero, multipliedBy, rightShift } from '@masknet/web3-shared-base' -import BigNumber from 'bignumber.js' -import { - NetworkPluginID, - TokenType, - useLookupAddress, - useNetworkDescriptor, - useWeb3State, - Web3Plugin, -} from '@masknet/plugin-infra' -import { FormattedAddress, TokenAmountPanel } from '@masknet/shared' import TuneIcon from '@mui/icons-material/Tune' +import { Box, Button, IconButton, Link, Popover, Stack, Typography } from '@mui/material' +import BigNumber from 'bignumber.js' +import { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react' +import { useUpdateEffect } from 'react-use' import { EthereumAddress } from 'wallet.ts' import { useDashboardI18N } from '../../../../locales' -import { useNativeTokenPrice } from './useNativeTokenPrice' import { useGasConfig } from '../../hooks/useGasConfig' -import { NetworkType } from '@masknet/public-api' -import { useUpdateEffect } from 'react-use' -import { v4 as uuid } from 'uuid' -import { PluginMessages } from '../../../../API' -import type { SelectTokenDialogEvent } from '@masknet/plugin-wallet' -import { RightIcon } from '@masknet/icons' +import { useNativeTokenPrice } from './useNativeTokenPrice' interface TransferERC20Props { token: FungibleTokenDetailed | Web3Plugin.FungibleToken @@ -50,7 +46,6 @@ export const TransferERC20 = memo(({ token }) => { const t = useDashboardI18N() const { NATIVE_TOKEN_ADDRESS } = useTokenConstants() const anchorEl = useRef(null) - const [id] = useState(uuid()) const [amount, setAmount] = useState('') const [address, setAddress] = useState('') const [memo, setMemo] = useState('') @@ -59,20 +54,10 @@ export const TransferERC20 = memo(({ token }) => { const network = useNetworkDescriptor() const [gasLimit_, setGasLimit_] = useState(0) - const { setDialog: setSelectToken } = useRemoteControlledDialog( - PluginMessages.Wallet.events.selectTokenDialogUpdated, - useCallback( - (ev: SelectTokenDialogEvent) => { - if (ev.open || !ev.token || ev.uuid !== id) return - setSelectedToken(ev.token) - }, - [id], - ), - ) - const { value: defaultGasPrice = '0' } = useGasPrice() const [selectedToken, setSelectedToken] = useState(token) + const pickToken = usePickToken() const chainId = useChainId() const is1559Supported = useMemo(() => isEIP1559Supported(chainId), [chainId]) @@ -297,12 +282,12 @@ export const TransferERC20 = memo(({ token }) => { SelectTokenChip={{ loading: false, ChipProps: { - onClick: () => - setSelectToken({ - open: true, - uuid: id, + onClick: async () => { + const pickedToken = await pickToken({ disableNativeToken: false, - }), + }) + if (pickedToken) setSelectedToken(pickedToken) + }, }, }} /> diff --git a/packages/dashboard/src/pages/Wallets/components/Transfer/TransferERC721.tsx b/packages/dashboard/src/pages/Wallets/components/Transfer/TransferERC721.tsx index ce5c581dcfa3..7e72ca73c272 100644 --- a/packages/dashboard/src/pages/Wallets/components/Transfer/TransferERC721.tsx +++ b/packages/dashboard/src/pages/Wallets/components/Transfer/TransferERC721.tsx @@ -75,7 +75,7 @@ export const TransferERC721 = memo(() => { } | null>(null) const [minPopoverWidth, setMinPopoverWidth] = useState(0) const [contract, setContract] = useState() - const [id] = useState(uuid()) + const [id] = useState(uuid) const [gasLimit_, setGasLimit_] = useState(0) const network = useNetworkDescriptor() const { Utils } = useWeb3State() diff --git a/packages/dashboard/tsconfig.json b/packages/dashboard/tsconfig.json index 6b383b331235..cfb7a22eb371 100644 --- a/packages/dashboard/tsconfig.json +++ b/packages/dashboard/tsconfig.json @@ -14,6 +14,7 @@ { "path": "../web3-shared/base/" }, { "path": "../web3-shared/evm/" }, { "path": "../web3-shared/flow/" }, + { "path": "../web3-shared/solana/" }, { "path": "../web3-providers" }, { "path": "../icons/" }, { "path": "../plugin-infra" }, diff --git a/packages/mask/shared-ui/locales/en-US.json b/packages/mask/shared-ui/locales/en-US.json index b8342b4b448a..5520be92abc7 100644 --- a/packages/mask/shared-ui/locales/en-US.json +++ b/packages/mask/shared-ui/locales/en-US.json @@ -124,7 +124,6 @@ "beta_sup": "(beta)", "post_dialog_plugins_experimental": "Plugins (Experimental)", "post_dialog__button": "Encrypt", - "post_dialog__dismiss_aria": "Dismiss the compose dialog", "post_dialog__image_payload": "Image Payload", "post_dialog__more_options_title": "More Options", "post_dialog__placeholder": "Text goes here…", diff --git a/packages/mask/shared-ui/locales/ja-JP.json b/packages/mask/shared-ui/locales/ja-JP.json index 516839e6c041..a178ed0c287c 100644 --- a/packages/mask/shared-ui/locales/ja-JP.json +++ b/packages/mask/shared-ui/locales/ja-JP.json @@ -47,7 +47,6 @@ "personas": "ペルソナ", "browser_action_enter_dashboard": "ダッシュボードに入る", "post_dialog__button": "完了", - "post_dialog__dismiss_aria": "作成ダイアログを閉じる", "post_dialog__image_payload": "画像で暗号化", "post_dialog__more_options_title": "他のオプション", "post_dialog__placeholder": "ここにテキストを持ってきます", diff --git a/packages/mask/shared-ui/locales/ko-KR.json b/packages/mask/shared-ui/locales/ko-KR.json index f95356fe192c..2e3c96d775ab 100644 --- a/packages/mask/shared-ui/locales/ko-KR.json +++ b/packages/mask/shared-ui/locales/ko-KR.json @@ -99,7 +99,6 @@ "beta_sup": "(beta)", "post_dialog_plugins_experimental": "Plugins (Experimental)", "post_dialog__button": "끝내기", - "post_dialog__dismiss_aria": "편집창을 닫기", "post_dialog__image_payload": "이미지 페이로드", "post_dialog__more_options_title": "추가 옵션", "post_dialog__placeholder": "여기서 텍스트 치기...", diff --git a/packages/mask/shared-ui/locales/qya-AA.json b/packages/mask/shared-ui/locales/qya-AA.json index cf87cc4ab822..ebad6607635f 100644 --- a/packages/mask/shared-ui/locales/qya-AA.json +++ b/packages/mask/shared-ui/locales/qya-AA.json @@ -123,7 +123,6 @@ "beta_sup": "crwdns10125:0crwdne10125:0", "post_dialog_plugins_experimental": "crwdns10127:0crwdne10127:0", "post_dialog__button": "crwdns4257:0crwdne4257:0", - "post_dialog__dismiss_aria": "crwdns4259:0crwdne4259:0", "post_dialog__image_payload": "crwdns4261:0crwdne4261:0", "post_dialog__more_options_title": "crwdns4263:0crwdne4263:0", "post_dialog__placeholder": "crwdns4265:0crwdne4265:0", diff --git a/packages/mask/shared-ui/locales/zh-CN.json b/packages/mask/shared-ui/locales/zh-CN.json index 233212b2f97d..7b1026789475 100644 --- a/packages/mask/shared-ui/locales/zh-CN.json +++ b/packages/mask/shared-ui/locales/zh-CN.json @@ -115,7 +115,6 @@ "beta_sup": "(测试版)", "post_dialog_plugins_experimental": "插件 (体验版)", "post_dialog__button": "加密", - "post_dialog__dismiss_aria": "关闭贴文发送对话框", "post_dialog__image_payload": "图片Payload", "post_dialog__more_options_title": "更多选项", "post_dialog__placeholder": "文本在此处…", diff --git a/packages/mask/shared-ui/locales/zh-TW.json b/packages/mask/shared-ui/locales/zh-TW.json index 3b743e3e12b6..a5d1157e8c64 100644 --- a/packages/mask/shared-ui/locales/zh-TW.json +++ b/packages/mask/shared-ui/locales/zh-TW.json @@ -76,7 +76,6 @@ "personas": "角色", "browser_action_enter_dashboard": "進入儀錶板", "post_dialog__button": "完成", - "post_dialog__dismiss_aria": "關閉發表貼文視窗", "post_dialog__image_payload": "圖片", "post_dialog__more_options_title": "更多選項", "post_dialog__placeholder": "在這裡輸入文字…", diff --git a/packages/mask/src/UIRoot.tsx b/packages/mask/src/UIRoot.tsx index 31d738d9740c..169c99453bfe 100644 --- a/packages/mask/src/UIRoot.tsx +++ b/packages/mask/src/UIRoot.tsx @@ -3,7 +3,7 @@ import { CustomSnackbarProvider } from '@masknet/theme' import { Web3Provider } from '@masknet/web3-shared-evm' import { CssBaseline, StyledEngineProvider, Theme, ThemeProvider } from '@mui/material' import { NetworkPluginID, PluginsWeb3ContextProvider, useAllPluginsWeb3State } from '@masknet/plugin-infra' -import { I18NextProviderHMR } from '@masknet/shared' +import { I18NextProviderHMR, SharedContextProvider } from '@masknet/shared' import { ErrorBoundary, ErrorBoundaryBuildInfoContext, useValueRef } from '@masknet/shared-base-ui' import i18nNextInstance from '../shared-ui/locales_legacy' import { Web3Context } from './web3/context' @@ -89,5 +89,6 @@ export function MaskUIRoot({ children, kind, useTheme }: MaskUIRootProps) { {jsx} ), + (jsx) => {jsx}, ) } diff --git a/packages/mask/src/components/CompositionDialog/Composition.tsx b/packages/mask/src/components/CompositionDialog/Composition.tsx index 99bb69510111..59889fd34719 100644 --- a/packages/mask/src/components/CompositionDialog/Composition.tsx +++ b/packages/mask/src/components/CompositionDialog/Composition.tsx @@ -5,7 +5,7 @@ import { activatedSocialNetworkUI, globalUIState } from '../../social-network' import { MaskMessages, useI18N } from '../../utils' import { CrossIsolationMessages } from '@masknet/shared-base' import { useFriendsList as useRecipientsList } from '../DataSource/useActivatedUI' -import { InjectedDialog } from '../shared/InjectedDialog' +import { InjectedDialog } from '@masknet/shared' import { CompositionDialogUI, CompositionRef } from './CompositionUI' import { useCompositionClipboardRequest } from './useCompositionClipboardRequest' import Services from '../../extension/service' diff --git a/packages/mask/src/components/InjectedComponents/CommentBox.tsx b/packages/mask/src/components/InjectedComponents/CommentBox.tsx index 9cd9d1e170b6..9bb17fb6473b 100644 --- a/packages/mask/src/components/InjectedComponents/CommentBox.tsx +++ b/packages/mask/src/components/InjectedComponents/CommentBox.tsx @@ -1,8 +1,8 @@ +import { MINDS_ID } from '@masknet/shared' import { makeStyles } from '@masknet/theme' -import { InputBase, Box } from '@mui/material' -import { useI18N } from '../../utils' +import { Box, InputBase } from '@mui/material' import { activatedSocialNetworkUI } from '../../social-network' -import { MINDS_ID } from '../../social-network-adaptor/minds.com/base' +import { useI18N } from '../../utils' interface StyleProps { snsId: string diff --git a/packages/mask/src/components/InjectedComponents/SelectPeopleDialog.tsx b/packages/mask/src/components/InjectedComponents/SelectPeopleDialog.tsx index b959a08b554d..613e77cfcf42 100644 --- a/packages/mask/src/components/InjectedComponents/SelectPeopleDialog.tsx +++ b/packages/mask/src/components/InjectedComponents/SelectPeopleDialog.tsx @@ -1,10 +1,10 @@ import { useCallback, useState } from 'react' import { makeStyles, useStylesExtends } from '@masknet/theme' import { Button, CircularProgress, DialogActions, DialogContent } from '@mui/material' +import { InjectedDialog } from '@masknet/shared' import { useI18N } from '../../utils' import { SelectProfileUI } from '../shared/SelectProfileUI' import type { Profile } from '../../database' -import { InjectedDialog } from '../shared/InjectedDialog' export interface SelectProfileDialogProps extends withClasses { open: boolean diff --git a/packages/mask/src/components/shared/DebugMetadataInspector.tsx b/packages/mask/src/components/shared/DebugMetadataInspector.tsx index c9fe24d2e9f1..ece4d17ed9b0 100644 --- a/packages/mask/src/components/shared/DebugMetadataInspector.tsx +++ b/packages/mask/src/components/shared/DebugMetadataInspector.tsx @@ -13,7 +13,7 @@ import { Autocomplete, } from '@mui/material' import ExpandMoreIcon from '@mui/icons-material/ExpandMore' -import { InjectedDialog } from './InjectedDialog' +import { InjectedDialog } from '@masknet/shared' import { isDataMatchJSONSchema, getKnownMetadataKeys, getMetadataSchema } from '@masknet/typed-message' import { ShadowRootPopper } from '@masknet/theme' import { useState } from 'react' diff --git a/packages/mask/src/components/shared/SelectRecipients/SelectRecipientsDialog.tsx b/packages/mask/src/components/shared/SelectRecipients/SelectRecipientsDialog.tsx index ed1824d6e973..57d6b484b1b6 100644 --- a/packages/mask/src/components/shared/SelectRecipients/SelectRecipientsDialog.tsx +++ b/packages/mask/src/components/shared/SelectRecipients/SelectRecipientsDialog.tsx @@ -1,11 +1,11 @@ -import { useState, useMemo } from 'react' -import Fuse from 'fuse.js' -import { List, ListItem, ListItemText, Button, InputBase, DialogContent, DialogActions } from '@mui/material' import { makeStyles, useStylesExtends } from '@masknet/theme' +import { InjectedDialog } from '@masknet/shared' +import { Button, DialogActions, DialogContent, InputBase, List, ListItem, ListItemText } from '@mui/material' +import Fuse from 'fuse.js' +import { useMemo, useState } from 'react' +import type { Profile } from '../../../database' import { useI18N } from '../../../utils' import { ProfileInList } from './ProfileInList' -import type { Profile } from '../../../database' -import { InjectedDialog } from '../InjectedDialog' const useStyles = makeStyles()((theme) => ({ content: { diff --git a/packages/mask/src/extension/popups/pages/Swap/index.tsx b/packages/mask/src/extension/popups/pages/Swap/index.tsx index 34727e3f5296..4adb25540b66 100644 --- a/packages/mask/src/extension/popups/pages/Swap/index.tsx +++ b/packages/mask/src/extension/popups/pages/Swap/index.tsx @@ -1,6 +1,7 @@ import { Appearance, applyMaskColorVars, makeStyles } from '@masknet/theme' import { TransactionStatusType, useChainId, useWallet, Web3Provider } from '@masknet/web3-shared-evm' import { ThemeProvider, Typography } from '@mui/material' +import { SharedContextProvider } from '@masknet/shared' import { useCallback } from 'react' import { useRecentTransactions } from '../../../../plugins/Wallet/hooks/useRecentTransactions' import Services from '../../../service' @@ -86,30 +87,32 @@ export default function SwapPage() { return ( -
-
-
- 0} - openConnectWalletDialog={openPopupsWindow} - walletName={wallet?.name} - domain={domain} - walletAddress={wallet?.address} - /> -
-
- - {t('plugin_trader_swap')} - - - - - - -
+ +
+
+
+ 0} + openConnectWalletDialog={openPopupsWindow} + walletName={wallet?.name} + domain={domain} + walletAddress={wallet?.address} + /> +
+
+ + {t('plugin_trader_swap')} + + + + + + +
+
-
+ ) diff --git a/packages/mask/src/plugins/ArtBlocks/SNSAdaptor/PurchaseDialog.tsx b/packages/mask/src/plugins/ArtBlocks/SNSAdaptor/PurchaseDialog.tsx index d53bbbbd27ac..b01ad22f3610 100644 --- a/packages/mask/src/plugins/ArtBlocks/SNSAdaptor/PurchaseDialog.tsx +++ b/packages/mask/src/plugins/ArtBlocks/SNSAdaptor/PurchaseDialog.tsx @@ -12,7 +12,6 @@ import { Typography, } from '@mui/material' import ActionButton from '../../../extension/options-page/DashboardComponents/ActionButton' -import { InjectedDialog } from '../../../components/shared/InjectedDialog' import { EthereumWalletConnectedBoundary } from '../../../web3/UI/EthereumWalletConnectedBoundary' import { ERC20TokenDetailed, @@ -23,11 +22,11 @@ import { TransactionStateType, } from '@masknet/web3-shared-evm' import { Trans } from 'react-i18next' -import { usePurchaseCallback } from '../hooks/usePurchaseCallback' -import { TokenAmountPanel } from '@masknet/shared' -import { EthereumERC20TokenApprovedBoundary } from '../../../web3/UI/EthereumERC20TokenApprovedBoundary' -import { leftShift } from '@masknet/web3-shared-base' import { useRemoteControlledDialog } from '@masknet/shared-base-ui' +import { InjectedDialog, TokenAmountPanel } from '@masknet/shared' +import { leftShift } from '@masknet/web3-shared-base' +import { EthereumERC20TokenApprovedBoundary } from '../../../web3/UI/EthereumERC20TokenApprovedBoundary' +import { usePurchaseCallback } from '../hooks/usePurchaseCallback' import { WalletMessages } from '../../Wallet/messages' import type { Project } from '../types' diff --git a/packages/mask/src/plugins/Avatar/SNSAdaptor/AddNFT.tsx b/packages/mask/src/plugins/Avatar/SNSAdaptor/AddNFT.tsx index a01ed117f905..97c7c707fe60 100644 --- a/packages/mask/src/plugins/Avatar/SNSAdaptor/AddNFT.tsx +++ b/packages/mask/src/plugins/Avatar/SNSAdaptor/AddNFT.tsx @@ -2,7 +2,7 @@ import { makeStyles } from '@masknet/theme' import { ERC721TokenDetailed, isSameAddress, useAccount } from '@masknet/web3-shared-evm' import { Button, DialogContent, Typography } from '@mui/material' import { useCallback, useState } from 'react' -import { InjectedDialog } from '../../../components/shared/InjectedDialog' +import { InjectedDialog } from '@masknet/shared' import { InputBox } from '../../../extension/options-page/DashboardComponents/InputBox' import { useI18N } from '../../../utils' import { createNFT } from '../utils' diff --git a/packages/mask/src/plugins/Collectible/SNSAdaptor/CheckoutDialog.tsx b/packages/mask/src/plugins/Collectible/SNSAdaptor/CheckoutDialog.tsx index 13fc32d6776e..bc520c67f29e 100644 --- a/packages/mask/src/plugins/Collectible/SNSAdaptor/CheckoutDialog.tsx +++ b/packages/mask/src/plugins/Collectible/SNSAdaptor/CheckoutDialog.tsx @@ -13,10 +13,10 @@ import { import { makeStyles } from '@masknet/theme' import { Trans } from 'react-i18next' import { EthereumTokenType, useAccount, useFungibleTokenWatched } from '@masknet/web3-shared-evm' -import { InjectedDialog } from '../../../components/shared/InjectedDialog' import { UnreviewedWarning } from './UnreviewedWarning' import { useI18N } from '../../../utils' import { useRemoteControlledDialog } from '@masknet/shared-base-ui' +import { InjectedDialog } from '@masknet/shared' import ActionButton, { ActionButtonPromise } from '../../../extension/options-page/DashboardComponents/ActionButton' import { EthereumWalletConnectedBoundary } from '../../../web3/UI/EthereumWalletConnectedBoundary' import { PluginCollectibleRPC } from '../messages' diff --git a/packages/mask/src/plugins/Collectible/SNSAdaptor/MakeOfferDialog.tsx b/packages/mask/src/plugins/Collectible/SNSAdaptor/MakeOfferDialog.tsx index fd1fef98b836..cd7c207be1eb 100644 --- a/packages/mask/src/plugins/Collectible/SNSAdaptor/MakeOfferDialog.tsx +++ b/packages/mask/src/plugins/Collectible/SNSAdaptor/MakeOfferDialog.tsx @@ -16,8 +16,8 @@ import BigNumber from 'bignumber.js' import { FungibleTokenDetailed, EthereumTokenType, useAccount, useFungibleTokenWatched } from '@masknet/web3-shared-evm' import formatDateTime from 'date-fns/format' import { useI18N } from '../../../utils' +import { InjectedDialog } from '@masknet/shared' import { useRemoteControlledDialog } from '@masknet/shared-base-ui' -import { InjectedDialog } from '../../../components/shared/InjectedDialog' import { UnreviewedWarning } from './UnreviewedWarning' import ActionButton, { ActionButtonPromise } from '../../../extension/options-page/DashboardComponents/ActionButton' import { EthereumWalletConnectedBoundary } from '../../../web3/UI/EthereumWalletConnectedBoundary' diff --git a/packages/mask/src/plugins/Collectible/SNSAdaptor/PostListingDialog.tsx b/packages/mask/src/plugins/Collectible/SNSAdaptor/PostListingDialog.tsx index 29ba310a63ed..524573ebd2ad 100644 --- a/packages/mask/src/plugins/Collectible/SNSAdaptor/PostListingDialog.tsx +++ b/packages/mask/src/plugins/Collectible/SNSAdaptor/PostListingDialog.tsx @@ -2,7 +2,7 @@ import { useState } from 'react' import { DialogContent, Tab, Tabs } from '@mui/material' import { makeStyles } from '@masknet/theme' import { useI18N } from '../../../utils' -import { InjectedDialog } from '../../../components/shared/InjectedDialog' +import { InjectedDialog } from '@masknet/shared' import { ListingByPriceCard } from './ListingByPriceCard' import { ListingByHighestBidCard } from './ListingByHighestBidCard' import { useFungibleTokenWatched } from '@masknet/web3-shared-evm' diff --git a/packages/mask/src/plugins/CryptoartAI/SNSAdaptor/CheckoutDialog.tsx b/packages/mask/src/plugins/CryptoartAI/SNSAdaptor/CheckoutDialog.tsx index 33cebe8fafbf..bd4e1683115d 100644 --- a/packages/mask/src/plugins/CryptoartAI/SNSAdaptor/CheckoutDialog.tsx +++ b/packages/mask/src/plugins/CryptoartAI/SNSAdaptor/CheckoutDialog.tsx @@ -4,11 +4,11 @@ import { makeStyles } from '@masknet/theme' import { first } from 'lodash-unified' import BigNumber from 'bignumber.js' import { useChainId, useFungibleTokenWatched, TransactionStateType, formatBalance } from '@masknet/web3-shared-evm' -import { InjectedDialog } from '../../../components/shared/InjectedDialog' +import { useRemoteControlledDialog } from '@masknet/shared-base-ui' +import { InjectedDialog } from '@masknet/shared' import { useI18N } from '../../../utils' import ActionButton from '../../../extension/options-page/DashboardComponents/ActionButton' import { EthereumWalletConnectedBoundary } from '../../../web3/UI/EthereumWalletConnectedBoundary' -import { useRemoteControlledDialog } from '@masknet/shared-base-ui' import { WalletMessages } from '../../Wallet/messages' import type { useAsset } from '../hooks/useAsset' import { resolvePaymentTokensOnCryptoartAI, resolveAssetLinkOnCryptoartAI } from '../pipes' diff --git a/packages/mask/src/plugins/CryptoartAI/SNSAdaptor/MakeOfferDialog.tsx b/packages/mask/src/plugins/CryptoartAI/SNSAdaptor/MakeOfferDialog.tsx index ebe26afb17a2..eb1a07ac67be 100644 --- a/packages/mask/src/plugins/CryptoartAI/SNSAdaptor/MakeOfferDialog.tsx +++ b/packages/mask/src/plugins/CryptoartAI/SNSAdaptor/MakeOfferDialog.tsx @@ -11,12 +11,12 @@ import { formatBalance, TransactionStateType, } from '@masknet/web3-shared-evm' +import { useRemoteControlledDialog } from '@masknet/shared-base-ui' +import { InjectedDialog } from '@masknet/shared' import { useI18N } from '../../../utils' -import { InjectedDialog } from '../../../components/shared/InjectedDialog' import ActionButton from '../../../extension/options-page/DashboardComponents/ActionButton' import { SelectTokenAmountPanel } from '../../ITO/SNSAdaptor/SelectTokenAmountPanel' import { EthereumWalletConnectedBoundary } from '../../../web3/UI/EthereumWalletConnectedBoundary' -import { useRemoteControlledDialog } from '@masknet/shared-base-ui' import { WalletMessages } from '../../Wallet/messages' import type { useAsset } from '../hooks/useAsset' import { resolvePaymentTokensOnCryptoartAI, resolveAssetLinkOnCryptoartAI } from '../pipes' diff --git a/packages/mask/src/plugins/EVM/messages.ts b/packages/mask/src/plugins/EVM/messages.ts index 8a8ea304aae9..28bf194d5b6d 100644 --- a/packages/mask/src/plugins/EVM/messages.ts +++ b/packages/mask/src/plugins/EVM/messages.ts @@ -25,8 +25,10 @@ export interface EVM_Messages { rpc: unknown } +const evmEventEmitter: PluginMessageEmitter = createPluginMessage(PLUGIN_ID, serializer) + export const EVM_Messages: { events: PluginMessageEmitter } = { - events: createPluginMessage(PLUGIN_ID, serializer), + events: evmEventEmitter, } export const EVM_RPC = createPluginRPC(PLUGIN_ID, () => import('./services'), EVM_Messages.events.rpc) diff --git a/packages/mask/src/plugins/External/components/CompositionEntry.tsx b/packages/mask/src/plugins/External/components/CompositionEntry.tsx index f27b2b708379..d24e9f18910e 100644 --- a/packages/mask/src/plugins/External/components/CompositionEntry.tsx +++ b/packages/mask/src/plugins/External/components/CompositionEntry.tsx @@ -4,7 +4,7 @@ import { DialogContent } from '@mui/material' import { useEffect } from 'react' import { MaskMessages, useI18N } from '../../../utils' import { PluginLoader } from './PluginLoader' -import { InjectedDialog } from '../../../components/shared/InjectedDialog' +import { InjectedDialog } from '@masknet/shared' export function ThirdPartyPluginCompositionEntry(props: Plugin.SNSAdaptor.CompositionDialogEntry_DialogProps) { const { t } = useI18N() diff --git a/packages/mask/src/plugins/FindTruman/SNSAdaptor/FindTrumanDialog.tsx b/packages/mask/src/plugins/FindTruman/SNSAdaptor/FindTrumanDialog.tsx index 990b9695b833..6450ab921425 100644 --- a/packages/mask/src/plugins/FindTruman/SNSAdaptor/FindTrumanDialog.tsx +++ b/packages/mask/src/plugins/FindTruman/SNSAdaptor/FindTrumanDialog.tsx @@ -1,6 +1,6 @@ import { Box, DialogContent } from '@mui/material' import { TabContext, TabPanel } from '@mui/lab' -import { InjectedDialog } from '../../../components/shared/InjectedDialog' +import { InjectedDialog } from '@masknet/shared' import { makeStyles, useStylesExtends, useTabs } from '@masknet/theme' import { WalletStatusBox } from '../../../components/shared/WalletStatusBox' import AbstractTab, { AbstractTabProps } from '../../../components/shared/AbstractTab' diff --git a/packages/mask/src/plugins/FindTruman/SNSAdaptor/MainDialog.tsx b/packages/mask/src/plugins/FindTruman/SNSAdaptor/MainDialog.tsx index d9af958dbc43..b2278b82343a 100644 --- a/packages/mask/src/plugins/FindTruman/SNSAdaptor/MainDialog.tsx +++ b/packages/mask/src/plugins/FindTruman/SNSAdaptor/MainDialog.tsx @@ -2,7 +2,7 @@ import { DialogContent, Card, Grid, Alert, Box, Typography, Button } from '@mui/ import { makeStyles } from '@masknet/theme' import { useContext, useEffect, useState } from 'react' import { useI18N } from '../../../utils' -import { InjectedDialog, InjectedDialogProps } from '../../../components/shared/InjectedDialog' +import { InjectedDialog, InjectedDialogProps } from '@masknet/shared' import { useAccount } from '@masknet/web3-shared-evm' import { fetchConst, fetchUserParticipatedStoryStatus } from '../Worker/apis' import type { UserStoryStatus, FindTrumanConst } from '../types' diff --git a/packages/mask/src/plugins/FindTruman/SNSAdaptor/ParticipatePanel.tsx b/packages/mask/src/plugins/FindTruman/SNSAdaptor/ParticipatePanel.tsx index b1453bdedc6b..2cabace3e88c 100644 --- a/packages/mask/src/plugins/FindTruman/SNSAdaptor/ParticipatePanel.tsx +++ b/packages/mask/src/plugins/FindTruman/SNSAdaptor/ParticipatePanel.tsx @@ -6,7 +6,7 @@ import { Box, Button, Card, DialogActions, DialogContent, Typography } from '@mu import { TabContext, TabPanel } from '@mui/lab' import StageCard from './StageCard' import { useControlledDialog } from '../../../utils' -import { InjectedDialog } from '../../../components/shared/InjectedDialog' +import { InjectedDialog } from '@masknet/shared' import { useCallback, useContext, useEffect, useMemo, useState } from 'react' import OptionsCard from './OptionsCard' import ResultCard from './ResultCard' diff --git a/packages/mask/src/plugins/FindTruman/SNSAdaptor/PartsPanel.tsx b/packages/mask/src/plugins/FindTruman/SNSAdaptor/PartsPanel.tsx index a6bcee3cb432..00ca5c8ba097 100644 --- a/packages/mask/src/plugins/FindTruman/SNSAdaptor/PartsPanel.tsx +++ b/packages/mask/src/plugins/FindTruman/SNSAdaptor/PartsPanel.tsx @@ -20,7 +20,7 @@ import { Typography, } from '@mui/material' import formatDateTime from 'date-fns/format' -import { InjectedDialog } from '../../../components/shared/InjectedDialog' +import { InjectedDialog } from '@masknet/shared' import { useContext, useMemo, useState } from 'react' import { LoadingButton } from '@mui/lab' import getUnixTime from 'date-fns/getUnixTime' diff --git a/packages/mask/src/plugins/Gitcoin/SNSAdaptor/DonateDialog.tsx b/packages/mask/src/plugins/Gitcoin/SNSAdaptor/DonateDialog.tsx index edf2dcfd6c97..fa58d7bee67e 100644 --- a/packages/mask/src/plugins/Gitcoin/SNSAdaptor/DonateDialog.tsx +++ b/packages/mask/src/plugins/Gitcoin/SNSAdaptor/DonateDialog.tsx @@ -1,3 +1,7 @@ +import { useRemoteControlledDialog } from '@masknet/shared-base-ui' +import { usePickToken, InjectedDialog } from '@masknet/shared' +import { makeStyles, useStylesExtends } from '@masknet/theme' +import { rightShift } from '@masknet/web3-shared-base' import { EthereumTokenType, formatBalance, @@ -5,29 +9,24 @@ import { TransactionStateType, useAccount, useChainId, + useFungibleTokenBalance, useGitcoinConstants, useNativeTokenDetailed, - useFungibleTokenBalance, } from '@masknet/web3-shared-evm' import { DialogContent, Link, Typography } from '@mui/material' -import { makeStyles, useStylesExtends } from '@masknet/theme' import { useCallback, useEffect, useMemo, useState } from 'react' import { Trans } from 'react-i18next' -import { v4 as uuid } from 'uuid' -import { InjectedDialog } from '../../../components/shared/InjectedDialog' import ActionButton from '../../../extension/options-page/DashboardComponents/ActionButton' import { activatedSocialNetworkUI } from '../../../social-network' -import { isTwitter } from '../../../social-network-adaptor/twitter.com/base' import { isFacebook } from '../../../social-network-adaptor/facebook.com/base' +import { isTwitter } from '../../../social-network-adaptor/twitter.com/base' import { useI18N } from '../../../utils' -import { useRemoteControlledDialog } from '@masknet/shared-base-ui' import { EthereumERC20TokenApprovedBoundary } from '../../../web3/UI/EthereumERC20TokenApprovedBoundary' import { EthereumWalletConnectedBoundary } from '../../../web3/UI/EthereumWalletConnectedBoundary' import { TokenAmountPanel } from '../../../web3/UI/TokenAmountPanel' -import { SelectTokenDialogEvent, WalletMessages } from '../../Wallet/messages' +import { WalletMessages } from '../../Wallet/messages' import { useDonateCallback } from '../hooks/useDonateCallback' import { PluginGitcoinMessages } from '../messages' -import { rightShift } from '@masknet/web3-shared-base' const useStyles = makeStyles()((theme) => ({ paper: { @@ -87,27 +86,14 @@ export function DonateDialog(props: DonateDialogProps) { // #endregion // #region select token dialog - const [id] = useState(uuid()) - const { setDialog: setSelectTokenDialog } = useRemoteControlledDialog( - WalletMessages.events.selectTokenDialogUpdated, - useCallback( - (ev: SelectTokenDialogEvent) => { - if (ev.open || !ev.token || ev.uuid !== id) return - setToken(ev.token) - }, - [id], - ), - ) - const onSelectTokenChipClick = useCallback(() => { - setSelectTokenDialog({ - open: true, - uuid: id, + const pickToken = usePickToken() + const onSelectTokenChipClick = useCallback(async () => { + const pickedToken = await pickToken({ disableNativeToken: false, - FungibleTokenListProps: { - selectedTokens: token ? [token.address] : [], - }, + selectedTokens: token?.address ? [token.address] : [], }) - }, [id, token?.address]) + if (pickedToken) setToken(pickedToken) + }, [pickToken, token?.address]) // #endregion // #region amount diff --git a/packages/mask/src/plugins/GoodGhosting/UI/GameActionDialog.tsx b/packages/mask/src/plugins/GoodGhosting/UI/GameActionDialog.tsx index 51ef10098ffb..5e02a0039cb7 100644 --- a/packages/mask/src/plugins/GoodGhosting/UI/GameActionDialog.tsx +++ b/packages/mask/src/plugins/GoodGhosting/UI/GameActionDialog.tsx @@ -1,6 +1,6 @@ import { Box, Button, DialogContent, DialogActions, Typography } from '@mui/material' import { makeStyles } from '@masknet/theme' -import { InjectedDialog } from '../../../components/shared/InjectedDialog' +import { InjectedDialog } from '@masknet/shared' import { EthereumWalletConnectedBoundary } from '../../../web3/UI/EthereumWalletConnectedBoundary' import { ERC20TokenDetailed, formatBalance, useERC20TokenBalance } from '@masknet/web3-shared-evm' import type { GoodGhostingInfo } from '../types' diff --git a/packages/mask/src/plugins/ITO/SNSAdaptor/ClaimAllDialog.tsx b/packages/mask/src/plugins/ITO/SNSAdaptor/ClaimAllDialog.tsx index cf8f32f94a2a..d58a66ae9710 100644 --- a/packages/mask/src/plugins/ITO/SNSAdaptor/ClaimAllDialog.tsx +++ b/packages/mask/src/plugins/ITO/SNSAdaptor/ClaimAllDialog.tsx @@ -3,8 +3,8 @@ import { useCallback, useEffect, useState, useLayoutEffect, useRef } from 'react import { flatten, uniq } from 'lodash-unified' import formatDateTime from 'date-fns/format' import { SnackbarProvider, makeStyles } from '@masknet/theme' -import { FormattedBalance } from '@masknet/shared' import { openWindow, useRemoteControlledDialog } from '@masknet/shared-base-ui' +import { InjectedDialog, FormattedBalance } from '@masknet/shared' import { DialogContent, CircularProgress, Typography, List, ListItem, useTheme } from '@mui/material' import { formatBalance, @@ -26,7 +26,6 @@ import { useI18N } from '../../../utils' import { Flags } from '../../../../shared' import { useSpaceStationCampaignInfo } from './hooks/useSpaceStationCampaignInfo' import { NftAirdropCard } from './NftAirdropCard' -import { InjectedDialog } from '../../../components/shared/InjectedDialog' import { useClaimAll } from './hooks/useClaimAll' import { WalletMessages } from '../../Wallet/messages' import { useClaimCallback } from './hooks/useClaimCallback' diff --git a/packages/mask/src/plugins/ITO/SNSAdaptor/CompositionDialog.tsx b/packages/mask/src/plugins/ITO/SNSAdaptor/CompositionDialog.tsx index 0057a4bb343a..2a09f23d9c3a 100644 --- a/packages/mask/src/plugins/ITO/SNSAdaptor/CompositionDialog.tsx +++ b/packages/mask/src/plugins/ITO/SNSAdaptor/CompositionDialog.tsx @@ -5,7 +5,7 @@ import { makeStyles } from '@masknet/theme' import { useI18N } from '../../../utils' import { useCurrentIdentity } from '../../../components/DataSource/useActivatedUI' import { useRemoteControlledDialog } from '@masknet/shared-base-ui' -import { InjectedDialog, InjectedDialogProps } from '../../../components/shared/InjectedDialog' +import { InjectedDialog, InjectedDialogProps, MINDS_ID } from '@masknet/shared' import { ITO_MetaKey_2, MSG_DELIMITER } from '../constants' import { DialogTabs, JSON_PayloadInMask } from '../types' import { CreateForm } from './CreateForm' @@ -20,7 +20,6 @@ import { ConfirmDialog } from './ConfirmDialog' import { WalletMessages } from '../../Wallet/messages' import { omit, set } from 'lodash-unified' import { useCompositionContext } from '@masknet/plugin-infra' -import { MINDS_ID } from '../../../social-network-adaptor/minds.com/base' import { activatedSocialNetworkUI } from '../../../social-network' interface StyleProps { diff --git a/packages/mask/src/plugins/ITO/SNSAdaptor/ExchangeTokenPanel.tsx b/packages/mask/src/plugins/ITO/SNSAdaptor/ExchangeTokenPanel.tsx index 096a903f9ff5..976730baf092 100644 --- a/packages/mask/src/plugins/ITO/SNSAdaptor/ExchangeTokenPanel.tsx +++ b/packages/mask/src/plugins/ITO/SNSAdaptor/ExchangeTokenPanel.tsx @@ -1,15 +1,14 @@ -import { EthereumTokenType, FungibleTokenDetailed, useFungibleTokenBalance } from '@masknet/web3-shared-evm' -import { IconButton, Paper } from '@mui/material' import { makeStyles } from '@masknet/theme' +import { EthereumTokenType, FungibleTokenDetailed, useFungibleTokenBalance } from '@masknet/web3-shared-evm' import AddIcon from '@mui/icons-material/AddOutlined' import RemoveIcon from '@mui/icons-material/RemoveOutlined' +import { IconButton, Paper } from '@mui/material' import { useCallback, useEffect, useState } from 'react' -import { v4 as uuid } from 'uuid' +import { usePickToken } from '@masknet/shared' import { useI18N } from '../../../utils' -import { useRemoteControlledDialog } from '@masknet/shared-base-ui' import type { TokenAmountPanelProps } from '../../../web3/UI/TokenAmountPanel' import { TokenAmountPanel } from '../../../web3/UI/TokenAmountPanel' -import { SelectTokenDialogEvent, WalletMessages } from '../../Wallet/messages' + const useStyles = makeStyles()((theme) => ({ root: { width: '100%', @@ -80,28 +79,21 @@ export function ExchangeTokenPanel(props: ExchangeTokenPanelProps) { const { t } = useI18N() const { classes } = useStyles() // #region select token dialog - const [id] = useState(uuid()) - const { setDialog: setSelectTokenDialog } = useRemoteControlledDialog( - WalletMessages.events.selectTokenDialogUpdated, - useCallback( - (ev: SelectTokenDialogEvent) => { - if (ev.open || !ev.token || ev.uuid !== id) return - onExchangeTokenChange(ev.token, dataIndex) - }, - [id, dataIndex], - ), - ) - const onSelectTokenChipClick = useCallback(() => { - setSelectTokenDialog({ - open: true, - uuid: id, + const pickToken = usePickToken() + const onSelectTokenChipClick = useCallback(async () => { + const picked = await pickToken({ disableNativeToken: isSell, - FungibleTokenListProps: { - blacklist: excludeTokensAddress, - selectedTokens: [exchangeToken?.address ?? '', ...selectedTokensAddress], - }, + blacklist: excludeTokensAddress, + selectedTokens: [exchangeToken?.address || '', ...selectedTokensAddress], }) - }, [id, isSell, exchangeToken, excludeTokensAddress.sort().join(), selectedTokensAddress.sort().join()]) + if (picked) onExchangeTokenChange(picked, dataIndex) + }, [ + isSell, + dataIndex, + exchangeToken?.address, + excludeTokensAddress.sort().join(), + selectedTokensAddress.sort().join(), + ]) // #endregion // #region balance diff --git a/packages/mask/src/plugins/ITO/SNSAdaptor/RegionSelect.tsx b/packages/mask/src/plugins/ITO/SNSAdaptor/RegionSelect.tsx index 780fe7f27453..c3096c60e708 100644 --- a/packages/mask/src/plugins/ITO/SNSAdaptor/RegionSelect.tsx +++ b/packages/mask/src/plugins/ITO/SNSAdaptor/RegionSelect.tsx @@ -1,6 +1,6 @@ import { useState, useRef, useCallback, forwardRef, useImperativeHandle, useMemo } from 'react' import type { InputBaseComponentProps } from '@mui/material' -import { makeStyles } from '@masknet/theme' +import { makeStyles, usePortalShadowRoot } from '@masknet/theme' import { useDebounce } from 'react-use' import { Typography, @@ -14,7 +14,7 @@ import { FilledInput, } from '@mui/material' -import { useI18N, usePortalShadowRoot } from '../../../utils' +import { useI18N } from '../../../utils' import { Flags } from '../../../../shared' import { useRegionList } from './hooks/useRegion' import type { RegionCode } from './hooks/useRegion' diff --git a/packages/mask/src/plugins/ITO/SNSAdaptor/SelectTokenAmountPanel.tsx b/packages/mask/src/plugins/ITO/SNSAdaptor/SelectTokenAmountPanel.tsx index 966b6db5d6b9..b367f351497e 100644 --- a/packages/mask/src/plugins/ITO/SNSAdaptor/SelectTokenAmountPanel.tsx +++ b/packages/mask/src/plugins/ITO/SNSAdaptor/SelectTokenAmountPanel.tsx @@ -1,9 +1,6 @@ -import { useState, useCallback } from 'react' -import { v4 as uuid } from 'uuid' +import { ERC20TokenListProps, usePickToken } from '@masknet/shared' import type { FungibleTokenDetailed } from '@masknet/web3-shared-evm' -import type { ERC20TokenListProps } from '@masknet/shared' -import { useRemoteControlledDialog } from '@masknet/shared-base-ui' -import { SelectTokenDialogEvent, WalletMessages } from '../../Wallet/messages' +import { useCallback } from 'react' import { TokenAmountPanel, TokenAmountPanelProps } from '../../../web3/UI/TokenAmountPanel' export interface SelectTokenAmountPanelProps { @@ -32,26 +29,15 @@ export function SelectTokenAmountPanel(props: SelectTokenAmountPanelProps) { } = props // #region select token - const [id] = useState(uuid()) - const { setDialog: setSelectTokenDialog } = useRemoteControlledDialog( - WalletMessages.events.selectTokenDialogUpdated, - useCallback( - (ev: SelectTokenDialogEvent) => { - if (ev.open || !ev.token || ev.uuid !== id) return - onTokenChange(ev.token) - }, - [id, onTokenChange], - ), - ) - const onSelectTokenChipClick = useCallback(() => { - setSelectTokenDialog({ - open: true, - uuid: id, + const pickToken = usePickToken() + const onSelectTokenChipClick = useCallback(async () => { + const picked = await pickToken({ disableNativeToken, disableSearchBar, - FungibleTokenListProps, + ...FungibleTokenListProps, }) - }, [id, disableNativeToken, disableSearchBar, FungibleTokenListProps]) + if (picked) onTokenChange(picked) + }, [disableNativeToken, disableSearchBar, FungibleTokenListProps]) // #endregion return ( diff --git a/packages/mask/src/plugins/ITO/SNSAdaptor/SwapDialog.tsx b/packages/mask/src/plugins/ITO/SNSAdaptor/SwapDialog.tsx index c8eb83b16790..de1be2f70f98 100644 --- a/packages/mask/src/plugins/ITO/SNSAdaptor/SwapDialog.tsx +++ b/packages/mask/src/plugins/ITO/SNSAdaptor/SwapDialog.tsx @@ -1,35 +1,35 @@ -import { useCallback, useEffect, useMemo, useState } from 'react' -import BigNumber from 'bignumber.js' -import { v4 as uuid } from 'uuid' -import { CircularProgress, Slider, Typography } from '@mui/material' -import { makeStyles, useStylesExtends } from '@masknet/theme' -import { useI18N } from '../../../utils' import { openWindow, useRemoteControlledDialog } from '@masknet/shared-base-ui' -import ActionButton from '../../../extension/options-page/DashboardComponents/ActionButton' +import { usePickToken } from '@masknet/shared' +import { makeStyles, useStylesExtends } from '@masknet/theme' +import { leftShift, rightShift, ZERO } from '@masknet/web3-shared-base' import { ChainId, currySameAddress, EthereumTokenType, formatBalance, FungibleTokenDetailed, + isNativeTokenAddress, + isSameAddress, resolveTransactionLinkOnExplorer, TransactionStateType, useChainId, useFungibleTokenBalance, useFungibleTokenDetailed, - isSameAddress, useTokenConstants, - isNativeTokenAddress, } from '@masknet/web3-shared-evm' -import { leftShift, rightShift, ZERO } from '@masknet/web3-shared-base' -import { SelectTokenDialogEvent, WalletMessages, WalletRPC } from '../../Wallet/messages' -import { TokenAmountPanel } from '../../../web3/UI/TokenAmountPanel' -import { useSwapCallback } from './hooks/useSwapCallback' -import type { JSON_PayloadInMask } from '../types' -import { SwapStatus } from './SwapGuide' +import { CircularProgress, Slider, Typography } from '@mui/material' +import BigNumber from 'bignumber.js' +import { useCallback, useEffect, useMemo, useState } from 'react' +import ActionButton from '../../../extension/options-page/DashboardComponents/ActionButton' +import { useI18N } from '../../../utils' import { EthereumERC20TokenApprovedBoundary } from '../../../web3/UI/EthereumERC20TokenApprovedBoundary' import { EthereumWalletConnectedBoundary } from '../../../web3/UI/EthereumWalletConnectedBoundary' +import { TokenAmountPanel } from '../../../web3/UI/TokenAmountPanel' +import { WalletMessages, WalletRPC } from '../../Wallet/messages' +import type { JSON_PayloadInMask } from '../types' import { useQualificationVerify } from './hooks/useQualificationVerify' +import { useSwapCallback } from './hooks/useSwapCallback' +import { SwapStatus } from './SwapGuide' const useStyles = makeStyles()((theme) => ({ button: { @@ -138,46 +138,25 @@ export function SwapDialog(props: SwapDialogProps) { swapAmount.isZero() ? '' : formatBalance(swapAmount, swapToken?.decimals), ) // #region select token - const [id] = useState(uuid()) - const { setDialog: setSelectTokenDialog } = useRemoteControlledDialog( - WalletMessages.events.selectTokenDialogUpdated, - useCallback( - (ev: SelectTokenDialogEvent) => { - if (ev.open || !ev.token || ev.uuid !== id) return - const at = exchangeTokens.findIndex(currySameAddress(ev.token!.address)) - const ratio = new BigNumber(payload.exchange_amounts[at * 2]).dividedBy( - payload.exchange_amounts[at * 2 + 1], - ) - setRatio(ratio) - setSwapToken(ev.token) - setTokenAmount(initAmount) - setSwapAmount(initAmount.multipliedBy(ratio)) - setInputAmountForUI( - initAmount.isZero() ? '' : formatBalance(initAmount.multipliedBy(ratio), ev.token.decimals), - ) - }, - [ - id, - payload, - initAmount, - exchangeTokens - .map((x) => x.address) - .sort() - .join(), - ], - ), - ) - const onSelectTokenChipClick = useCallback(() => { - setSelectTokenDialog({ - open: true, - uuid: id, + const pickToken = usePickToken() + const onSelectTokenChipClick = useCallback(async () => { + const picked = await pickToken({ disableNativeToken: !exchangeTokens.some(isNativeTokenAddress), disableSearchBar: true, - FungibleTokenListProps: { - whitelist: exchangeTokens.map((x) => x.address), - }, + whitelist: exchangeTokens.map((x) => x.address), }) + if (!picked) return + const at = exchangeTokens.findIndex(currySameAddress(picked.address)) + const ratio = new BigNumber(payload.exchange_amounts[at * 2]).dividedBy(payload.exchange_amounts[at * 2 + 1]) + setRatio(ratio) + setSwapToken(picked) + setTokenAmount(initAmount) + setSwapAmount(initAmount.multipliedBy(ratio)) + setInputAmountForUI(initAmount.isZero() ? '' : formatBalance(initAmount.multipliedBy(ratio), picked.decimals)) }, [ + initAmount, + payload, + pickToken, exchangeTokens .map((x) => x.address) .sort() diff --git a/packages/mask/src/plugins/ITO/SNSAdaptor/SwapGuide.tsx b/packages/mask/src/plugins/ITO/SNSAdaptor/SwapGuide.tsx index 962a662858a1..429c546fcb71 100644 --- a/packages/mask/src/plugins/ITO/SNSAdaptor/SwapGuide.tsx +++ b/packages/mask/src/plugins/ITO/SNSAdaptor/SwapGuide.tsx @@ -4,7 +4,7 @@ import { DialogContent } from '@mui/material' import { makeStyles } from '@masknet/theme' import BigNumber from 'bignumber.js' import { useCallback, useEffect, useMemo, useState, useTransition } from 'react' -import { InjectedDialog, InjectedDialogProps } from '../../../components/shared/InjectedDialog' +import { InjectedDialog, InjectedDialogProps } from '@masknet/shared' import { useI18N } from '../../../utils' import { RemindDialog } from './RemindDialog' import { ShareDialog } from './ShareDialog' diff --git a/packages/mask/src/plugins/ITO/SNSAdaptor/UnlockDialog.tsx b/packages/mask/src/plugins/ITO/SNSAdaptor/UnlockDialog.tsx index c2ba6a47acf5..39afec2f26fe 100644 --- a/packages/mask/src/plugins/ITO/SNSAdaptor/UnlockDialog.tsx +++ b/packages/mask/src/plugins/ITO/SNSAdaptor/UnlockDialog.tsx @@ -1,12 +1,7 @@ -import { Link, Typography } from '@mui/material' import { makeStyles } from '@masknet/theme' +import { isGreaterThan, rightShift } from '@masknet/web3-shared-base' import { useCallback, useState } from 'react' -import { v4 as uuid } from 'uuid' -import { useRemoteControlledDialog } from '@masknet/shared-base-ui' -import { useI18N } from '../../../utils' -import ActionButton from '../../../extension/options-page/DashboardComponents/ActionButton' import { - useITOConstants, ERC20TokenDetailed, EthereumTokenType, formatBalance, @@ -14,13 +9,16 @@ import { resolveAddressLinkOnExplorer, useChainId, useFungibleTokenBalance, + useITOConstants, } from '@masknet/web3-shared-evm' -import { isGreaterThan, rightShift } from '@masknet/web3-shared-base' +import { Link, Typography } from '@mui/material' +import { Trans } from 'react-i18next' +import { usePickToken } from '@masknet/shared' +import ActionButton from '../../../extension/options-page/DashboardComponents/ActionButton' +import { useI18N } from '../../../utils' import { EthereumERC20TokenApprovedBoundary } from '../../../web3/UI/EthereumERC20TokenApprovedBoundary' import { EthereumWalletConnectedBoundary } from '../../../web3/UI/EthereumWalletConnectedBoundary' import { TokenAmountPanel } from '../../../web3/UI/TokenAmountPanel' -import { SelectTokenDialogEvent, WalletMessages } from '../../Wallet/messages' -import { Trans } from 'react-i18next' function isMoreThanMillion(allowance: string, decimals: number) { return isGreaterThan(allowance, `100000000000e${decimals}`) // 100 billion @@ -51,30 +49,16 @@ export function UnlockDialog(props: UnlockDialogProps) { // #region select token const [token, setToken] = useState(tokens[0]) - const [id] = useState(uuid()) - const { setDialog: setSelectTokenDialog } = useRemoteControlledDialog( - WalletMessages.events.selectTokenDialogUpdated, - useCallback( - (ev: SelectTokenDialogEvent) => { - if (ev.open || !ev.token || ev.uuid !== id) return - if (ev.token.type !== EthereumTokenType.ERC20) return - setToken(ev.token) - }, - [id], - ), - ) - const onSelectTokenChipClick = useCallback(() => { - setSelectTokenDialog({ - open: true, - uuid: id, + const pickToken = usePickToken() + const onSelectTokenChipClick = useCallback(async () => { + const picked = await pickToken({ disableNativeToken: true, disableSearchBar: true, - FungibleTokenListProps: { - selectedTokens: token ? [token.address] : [], - whitelist: tokens.map((x) => x.address), - }, + selectedTokens: token?.address ? [token.address] : [], + whitelist: tokens.map((x) => x.address), }) - }, [id, token?.address]) + if (picked) setToken(picked as ERC20TokenDetailed) + }, [tokens, token?.address]) // #endregion // #region amount const [rawAmount, setRawAmount] = useState('') diff --git a/packages/mask/src/plugins/MaskBox/SNSAdaptor/components/DrawDialog.tsx b/packages/mask/src/plugins/MaskBox/SNSAdaptor/components/DrawDialog.tsx index 3175cd46946c..3b54781299a1 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 { useContainer } from 'unstated-next' import { makeStyles } from '@masknet/theme' import { Add, Remove } from '@mui/icons-material' import { useProviderDescriptor } from '@masknet/plugin-infra' -import { FormattedAddress, FormattedBalance, ImageIcon } from '@masknet/shared' +import { FormattedAddress, FormattedBalance, ImageIcon, InjectedDialog } from '@masknet/shared' import { Box, Button, DialogContent, TextField, Typography } from '@mui/material' import { formatBalance, @@ -13,7 +13,6 @@ import { useMaskBoxConstants, EthereumTokenType, } from '@masknet/web3-shared-evm' -import { InjectedDialog } from '../../../../components/shared/InjectedDialog' import ActionButton from '../../../../extension/options-page/DashboardComponents/ActionButton' import { EthereumERC20TokenApprovedBoundary } from '../../../../web3/UI/EthereumERC20TokenApprovedBoundary' import { EthereumWalletConnectedBoundary } from '../../../../web3/UI/EthereumWalletConnectedBoundary' diff --git a/packages/mask/src/plugins/MaskBox/SNSAdaptor/components/DrawResultDialog.tsx b/packages/mask/src/plugins/MaskBox/SNSAdaptor/components/DrawResultDialog.tsx index efc34c74250e..cbcd770a0b99 100644 --- a/packages/mask/src/plugins/MaskBox/SNSAdaptor/components/DrawResultDialog.tsx +++ b/packages/mask/src/plugins/MaskBox/SNSAdaptor/components/DrawResultDialog.tsx @@ -5,7 +5,7 @@ import { Box, DialogContent } from '@mui/material' import type { ERC721ContractDetailed } from '@masknet/web3-shared-evm' import type { BoxInfo } from '../../type' import { TokenCard } from './TokenCard' -import { InjectedDialog } from '../../../../components/shared/InjectedDialog' +import { InjectedDialog } from '@masknet/shared' import ActionButton from '../../../../extension/options-page/DashboardComponents/ActionButton' import { activatedSocialNetworkUI } from '../../../../social-network' import { usePostLink } from '../../../../components/DataSource/usePostInfo' diff --git a/packages/mask/src/plugins/NextID/components/BindPanelUI.tsx b/packages/mask/src/plugins/NextID/components/BindPanelUI.tsx index 74b2cc741ca2..886164d5a15e 100644 --- a/packages/mask/src/plugins/NextID/components/BindPanelUI.tsx +++ b/packages/mask/src/plugins/NextID/components/BindPanelUI.tsx @@ -7,10 +7,9 @@ import DoneIcon from '@mui/icons-material/Done' import { useI18N } from '../locales' import { getMaskColor, makeStyles, MaskColorVar } from '@masknet/theme' import type { Persona } from '../../../database' -import { LoadingAnimation } from '@masknet/shared' -import { formatPersonaFingerprint } from '@masknet/shared-base' -import { InjectedDialog } from '../../../components/shared/InjectedDialog' +import { InjectedDialog, LoadingAnimation } from '@masknet/shared' import { NetworkPluginID, useCurrentWeb3NetworkPluginID } from '@masknet/plugin-infra' +import { formatPersonaFingerprint } from '@masknet/shared-base' const useStyles = makeStyles()((theme) => ({ persona: { diff --git a/packages/mask/src/plugins/NextID/components/ConfirmModal.tsx b/packages/mask/src/plugins/NextID/components/ConfirmModal.tsx index 2e619b520f55..bae9341cd67d 100644 --- a/packages/mask/src/plugins/NextID/components/ConfirmModal.tsx +++ b/packages/mask/src/plugins/NextID/components/ConfirmModal.tsx @@ -1,7 +1,7 @@ import { makeStyles } from '@masknet/theme' import { Button, DialogActions, DialogContent, Typography } from '@mui/material' import type { FC, ReactNode } from 'react' -import { InjectedDialog, InjectedDialogProps } from '../../../components/shared/InjectedDialog' +import { InjectedDialog, InjectedDialogProps } from '@masknet/shared' const useStyles = makeStyles()((theme) => ({ confirmDialog: { diff --git a/packages/mask/src/plugins/NextID/components/Tip/TipDialog.tsx b/packages/mask/src/plugins/NextID/components/Tip/TipDialog.tsx index eaa9f4faebeb..aa6a349703ba 100644 --- a/packages/mask/src/plugins/NextID/components/Tip/TipDialog.tsx +++ b/packages/mask/src/plugins/NextID/components/Tip/TipDialog.tsx @@ -1,14 +1,13 @@ import { SuccessIcon } from '@masknet/icons' import { PluginId, useActivatedPlugin, useCurrentWeb3NetworkPluginID } from '@masknet/plugin-infra' -import { NFTCardStyledAssetPlayer } from '@masknet/shared' -import { openWindow } from '@masknet/shared-base-ui' +import { InjectedDialog, NFTCardStyledAssetPlayer } from '@masknet/shared' import { EMPTY_LIST } from '@masknet/shared-base' +import { openWindow } from '@masknet/shared-base-ui' import { makeStyles } from '@masknet/theme' import { TransactionStateType, useChainId, useERC721TokenDetailed } from '@masknet/web3-shared-evm' import { DialogContent, Typography } from '@mui/material' import { useCallback, useEffect, useMemo } from 'react' import { useBoolean } from 'react-use' -import { InjectedDialog } from '../../../../components/shared/InjectedDialog' import { NetworkTab } from '../../../../components/shared/NetworkTab' import { activatedSocialNetworkUI } from '../../../../social-network' import { TargetChainIdContext, useTip } from '../../contexts' diff --git a/packages/mask/src/plugins/NextID/components/Tip/TipForm.tsx b/packages/mask/src/plugins/NextID/components/Tip/TipForm.tsx index 208680a59c5a..b8c731e49afd 100644 --- a/packages/mask/src/plugins/NextID/components/Tip/TipForm.tsx +++ b/packages/mask/src/plugins/NextID/components/Tip/TipForm.tsx @@ -1,12 +1,12 @@ import { useWeb3State } from '@masknet/plugin-infra' -import { SelectTokenDialogEvent, WalletMessages } from '@masknet/plugin-wallet' +import { WalletMessages } from '@masknet/plugin-wallet' +import { usePickToken } from '@masknet/shared' import { useRemoteControlledDialog } from '@masknet/shared-base-ui' import { makeStyles } from '@masknet/theme' import { EthereumTokenType, useAccount, useFungibleTokenBalance } from '@masknet/web3-shared-evm' import { Box, BoxProps, FormControl, MenuItem, Select, Typography } from '@mui/material' import classnames from 'classnames' -import { FC, memo, useCallback, useRef, useState } from 'react' -import { v4 as uuid } from 'uuid' +import { FC, memo, useCallback, useRef } from 'react' import ActionButton from '../../../../extension/options-page/DashboardComponents/ActionButton' import { EthereumChainBoundary } from '../../../../web3/UI/EthereumChainBoundary' import { TokenAmountPanel } from '../../../../web3/UI/TokenAmountPanel' @@ -73,32 +73,21 @@ export const TipForm: FC = memo(({ className, ...rest }) => { const [isValid, validateMessage] = useTipValidate() const { Utils } = useWeb3State() const selectRef = useRef(null) - const [id] = useState(uuid) const account = useAccount() const { openDialog: openSelectProviderDialog } = useRemoteControlledDialog( WalletMessages.events.selectProviderDialogUpdated, ) - const { setDialog: setSelectTokenDialog } = useRemoteControlledDialog( - WalletMessages.events.selectTokenDialogUpdated, - useCallback( - (ev: SelectTokenDialogEvent) => { - if (ev.open || !ev.token || ev.uuid !== id) return - setToken(ev.token) - }, - [id], - ), - ) - const onSelectTokenChipClick = useCallback(() => { - setSelectTokenDialog({ + const pickToken = usePickToken() + const onSelectTokenChipClick = useCallback(async () => { + const picked = await pickToken({ chainId, - open: true, - uuid: id, disableNativeToken: false, - FungibleTokenListProps: { - selectedTokens: token ? [token.address] : [], - }, + selectedTokens: token ? [token.address] : [], }) - }, [id, token?.address, chainId]) + if (picked) { + setToken(picked) + } + }, [pickToken, token?.address, chainId]) // balance const { value: tokenBalance = '0', loading: loadingTokenBalance } = useFungibleTokenBalance( diff --git a/packages/mask/src/plugins/NextID/components/UnbindPanelUI.tsx b/packages/mask/src/plugins/NextID/components/UnbindPanelUI.tsx index c54656b32760..ab18c807d452 100644 --- a/packages/mask/src/plugins/NextID/components/UnbindPanelUI.tsx +++ b/packages/mask/src/plugins/NextID/components/UnbindPanelUI.tsx @@ -7,11 +7,10 @@ import DoneIcon from '@mui/icons-material/Done' import { useI18N } from '../locales' import { getMaskColor, makeStyles, MaskColorVar } from '@masknet/theme' import type { Persona } from '../../../database' -import { LoadingAnimation } from '@masknet/shared' -import { formatPersonaFingerprint } from '@masknet/shared-base' -import { InjectedDialog } from '../../../components/shared/InjectedDialog' +import { InjectedDialog, LoadingAnimation } from '@masknet/shared' import { NetworkPluginID, useCurrentWeb3NetworkPluginID } from '@masknet/plugin-infra' import AbstractTab, { AbstractTabProps } from '../../../components/shared/AbstractTab' +import { formatPersonaFingerprint } from '@masknet/shared-base' const useStyles = makeStyles()((theme) => ({ persona: { diff --git a/packages/mask/src/plugins/Pets/SNSAdaptor/PetDialog.tsx b/packages/mask/src/plugins/Pets/SNSAdaptor/PetDialog.tsx index b9efb0a31221..43b6a5c96385 100644 --- a/packages/mask/src/plugins/Pets/SNSAdaptor/PetDialog.tsx +++ b/packages/mask/src/plugins/Pets/SNSAdaptor/PetDialog.tsx @@ -2,9 +2,9 @@ import { useState } from 'react' import { useAsync, useTimeout } from 'react-use' import type { Constant } from '@masknet/web3-shared-evm/constants/utils' import { useRemoteControlledDialog } from '@masknet/shared-base-ui' +import { InjectedDialog } from '@masknet/shared' import { DialogContent } from '@mui/material' import { PluginPetMessages, PluginPetRPC } from '../messages' -import { InjectedDialog } from '../../../components/shared/InjectedDialog' import { useI18N } from '../../../utils' import { PetShareDialog } from './PetShareDialog' import { PetSetDialog } from './PetSetDialog' diff --git a/packages/mask/src/plugins/Polls/SNSAdaptor/PollsDialog.tsx b/packages/mask/src/plugins/Polls/SNSAdaptor/PollsDialog.tsx index 66df37c2f593..ce0ff662c48f 100644 --- a/packages/mask/src/plugins/Polls/SNSAdaptor/PollsDialog.tsx +++ b/packages/mask/src/plugins/Polls/SNSAdaptor/PollsDialog.tsx @@ -15,6 +15,7 @@ import { import { makeStyles, useStylesExtends, usePortalShadowRoot } from '@masknet/theme' import AddIcon from '@mui/icons-material/Add' import addDate from 'date-fns/add' +import { InjectedDialog } from '@masknet/shared' import { useI18N } from '../../../utils' import AbstractTab, { AbstractTabProps } from '../../../components/shared/AbstractTab' import { useCurrentIdentity } from '../../../components/DataSource/useActivatedUI' @@ -22,7 +23,6 @@ import type { PollGunDB } from '../Services' import { PollCardUI } from './Polls' import type { PollMetaData } from '../types' import { PLUGIN_META_KEY } from '../constants' -import { InjectedDialog } from '../../../components/shared/InjectedDialog' import { PluginPollRPC } from '../messages' import { useCompositionContext } from '@masknet/plugin-infra' diff --git a/packages/mask/src/plugins/PoolTogether/UI/DepositDialog.tsx b/packages/mask/src/plugins/PoolTogether/UI/DepositDialog.tsx index bce5d39ccd42..552221d0c1e5 100644 --- a/packages/mask/src/plugins/PoolTogether/UI/DepositDialog.tsx +++ b/packages/mask/src/plugins/PoolTogether/UI/DepositDialog.tsx @@ -1,21 +1,21 @@ import { useRemoteControlledDialog } from '@masknet/shared-base-ui' +import { usePickToken, InjectedDialog } from '@masknet/shared' +import { keyframes, makeStyles } from '@masknet/theme' +import { isZero, rightShift } from '@masknet/web3-shared-base' import { EthereumTokenType, formatBalance, FungibleTokenDetailed, TransactionStateType, useAccount, - ZERO_ADDRESS, useFungibleTokenBalance, + ZERO_ADDRESS, } from '@masknet/web3-shared-evm' -import { isZero, rightShift } from '@masknet/web3-shared-base' import { DialogContent, Grid, Typography } from '@mui/material' -import { keyframes, makeStyles } from '@masknet/theme' import { useCallback, useEffect, useMemo, useState } from 'react' -import { v4 as uuid } from 'uuid' -import { InjectedDialog } from '../../../components/shared/InjectedDialog' import ActionButton from '../../../extension/options-page/DashboardComponents/ActionButton' import { activatedSocialNetworkUI } from '../../../social-network' +import { isFacebook } from '../../../social-network-adaptor/facebook.com/base' import { isTwitter } from '../../../social-network-adaptor/twitter.com/base' import { useI18N } from '../../../utils/i18n-next-ui' import { EthereumERC20TokenApprovedBoundary } from '../../../web3/UI/EthereumERC20TokenApprovedBoundary' @@ -23,12 +23,11 @@ import { EthereumWalletConnectedBoundary } from '../../../web3/UI/EthereumWallet import { TokenAmountPanel } from '../../../web3/UI/TokenAmountPanel' import { PluginTraderMessages } from '../../Trader/messages' import type { Coin } from '../../Trader/types' -import { SelectTokenDialogEvent, WalletMessages } from '../../Wallet/messages' +import { WalletMessages } from '../../Wallet/messages' import { useDepositCallback } from '../hooks/useDepositCallback' import { PluginPoolTogetherMessages } from '../messages' import type { Pool } from '../types' import { calculateOdds, getPrizePeriod } from '../utils' -import { isFacebook } from '../../../social-network-adaptor/facebook.com/base' const rainbow_animation = keyframes` 0% { @@ -82,7 +81,6 @@ const useStyles = makeStyles()((theme) => ({ export function DepositDialog() { const { t } = useI18N() const { classes } = useStyles() - const [id] = useState(uuid()) const [pool, setPool] = useState() const [token, setToken] = useState() const [odds, setOdds] = useState() @@ -102,28 +100,16 @@ export function DepositDialog() { // #endregion // #region select token - const { setDialog: setSelectTokenDialogOpen } = useRemoteControlledDialog( - WalletMessages.events.selectTokenDialogUpdated, - useCallback( - (ev: SelectTokenDialogEvent) => { - if (ev.open || !ev.token || ev.uuid !== id) return - setToken(ev.token) - }, - [id], - ), - ) - const onSelectTokenChipClick = useCallback(() => { + const pickToken = usePickToken() + const onSelectTokenChipClick = useCallback(async () => { if (!token) return - setSelectTokenDialogOpen({ - open: true, - uuid: id, + const picked = await pickToken({ disableNativeToken: true, - FungibleTokenListProps: { - selectedTokens: [token.address], - whitelist: [token.address], - }, + selectedTokens: [token.address], + whitelist: [token.address], }) - }, [id, token?.address]) + if (picked) setToken(picked) + }, [token, pickToken]) // #endregion // #region amount @@ -216,7 +202,7 @@ export function DepositDialog() { if (depositState.type === TransactionStateType.HASH) setRawAmount('') resetDepositCallback() }, - [id, depositState, retryLoadTokenBalance, retryLoadTokenBalance, onClose], + [depositState, retryLoadTokenBalance, retryLoadTokenBalance, onClose], ), ) diff --git a/packages/mask/src/plugins/RedPacket/SNSAdaptor/RedPacketCreateNew.tsx b/packages/mask/src/plugins/RedPacket/SNSAdaptor/RedPacketCreateNew.tsx index 2c1107f5b84f..22a399ef1503 100644 --- a/packages/mask/src/plugins/RedPacket/SNSAdaptor/RedPacketCreateNew.tsx +++ b/packages/mask/src/plugins/RedPacket/SNSAdaptor/RedPacketCreateNew.tsx @@ -1,10 +1,10 @@ import { makeStyles } from '@masknet/theme' +import { MINDS_ID } from '@masknet/shared' import { useChainId, ChainId } from '@masknet/web3-shared-evm' import { RedPacketFormProps, RedPacketERC20Form } from './RedPacketERC20Form' import { RedPacketERC721Form } from './RedPacketERC721Form' import AbstractTab, { AbstractTabProps } from '../../../components/shared/AbstractTab' import { useI18N } from '../../../utils' -import { MINDS_ID } from '../../../social-network-adaptor/minds.com/base' import { activatedSocialNetworkUI } from '../../../social-network' import { IconURLs } from './IconURL' diff --git a/packages/mask/src/plugins/RedPacket/SNSAdaptor/RedPacketDialog.tsx b/packages/mask/src/plugins/RedPacket/SNSAdaptor/RedPacketDialog.tsx index 919c9432e430..953069f0ff3c 100644 --- a/packages/mask/src/plugins/RedPacket/SNSAdaptor/RedPacketDialog.tsx +++ b/packages/mask/src/plugins/RedPacket/SNSAdaptor/RedPacketDialog.tsx @@ -2,6 +2,7 @@ import { useState, useCallback, useRef, useMemo, useEffect } from 'react' import { DialogContent } from '@mui/material' import { usePortalShadowRoot, makeStyles } from '@masknet/theme' import { useRemoteControlledDialog } from '@masknet/shared-base-ui' +import { InjectedDialog } from '@masknet/shared' import { useI18N } from '../../../utils' import AbstractTab, { AbstractTabProps } from '../../../components/shared/AbstractTab' import { RedPacketJSONPayload, DialogTabs, RedPacketRecord, RpTypeTabs } from '../types' @@ -9,7 +10,6 @@ import { RedPacketRPC } from '../messages' import { RedPacketMetaKey } from '../constants' import { RedPacketCreateNew } from './RedPacketCreateNew' import { RedPacketPast } from './RedPacketPast' -import { InjectedDialog } from '../../../components/shared/InjectedDialog' import Services from '../../../extension/service' import Web3Utils from 'web3-utils' import { diff --git a/packages/mask/src/plugins/RedPacket/SNSAdaptor/RedPacketERC20Form.tsx b/packages/mask/src/plugins/RedPacket/SNSAdaptor/RedPacketERC20Form.tsx index 2bf6f54f6503..6e0673921c71 100644 --- a/packages/mask/src/plugins/RedPacket/SNSAdaptor/RedPacketERC20Form.tsx +++ b/packages/mask/src/plugins/RedPacket/SNSAdaptor/RedPacketERC20Form.tsx @@ -1,28 +1,26 @@ -import { useRemoteControlledDialog } from '@masknet/shared-base-ui' +import { makeStyles, useStylesExtends } from '@masknet/theme' +import { isGreaterThan, isZero, multipliedBy, rightShift } from '@masknet/web3-shared-base' import { EthereumTokenType, formatBalance, FungibleTokenDetailed, useAccount, + useChainId, + useFungibleTokenBalance, useNativeTokenDetailed, useRedPacketConstants, - useFungibleTokenBalance, - useChainId, } from '@masknet/web3-shared-evm' -import { isGreaterThan, isZero, multipliedBy, rightShift } from '@masknet/web3-shared-base' -import { omit } from 'lodash-unified' import { FormControl, InputLabel, MenuItem, MenuProps, Select, TextField } from '@mui/material' -import { makeStyles, useStylesExtends } from '@masknet/theme' import BigNumber from 'bignumber.js' -import { ChangeEvent, useCallback, useMemo, useState, useEffect } from 'react' -import { v4 as uuid } from 'uuid' +import { omit } from 'lodash-unified' +import { ChangeEvent, useCallback, useEffect, useMemo, useState } from 'react' +import { usePickToken } from '@masknet/shared' import { useCurrentIdentity } from '../../../components/DataSource/useActivatedUI' import ActionButton from '../../../extension/options-page/DashboardComponents/ActionButton' import { useI18N } from '../../../utils' import { EthereumERC20TokenApprovedBoundary } from '../../../web3/UI/EthereumERC20TokenApprovedBoundary' import { EthereumWalletConnectedBoundary } from '../../../web3/UI/EthereumWalletConnectedBoundary' import { TokenAmountPanel } from '../../../web3/UI/TokenAmountPanel' -import { SelectTokenDialogEvent, WalletMessages } from '../../Wallet/messages' import { RED_PACKET_DEFAULT_SHARES, RED_PACKET_MAX_SHARES, RED_PACKET_MIN_SHARES } from '../constants' import type { RedPacketSettings } from './hooks/useCreateCallback' @@ -96,27 +94,14 @@ export function RedPacketERC20Form(props: RedPacketFormProps) { // #region select token const { value: nativeTokenDetailed } = useNativeTokenDetailed() const [token = nativeTokenDetailed, setToken] = useState(origin?.token) - const [id] = useState(uuid) - const { setDialog: setSelectTokenDialog } = useRemoteControlledDialog( - WalletMessages.events.selectTokenDialogUpdated, - useCallback( - (ev: SelectTokenDialogEvent) => { - if (ev.open || !ev.token || ev.uuid !== id) return - setToken(ev.token) - }, - [id], - ), - ) - const onSelectTokenChipClick = useCallback(() => { - setSelectTokenDialog({ - open: true, - uuid: id, + const pickToken = usePickToken() + const onSelectTokenChipClick = useCallback(async () => { + const picked = await pickToken({ disableNativeToken: false, - FungibleTokenListProps: { - selectedTokens: token ? [token.address] : [], - }, + selectedTokens: token ? [token.address] : [], }) - }, [id, token?.address]) + if (picked) setToken(picked) + }, [pickToken, token?.address]) // #endregion // #region packet settings diff --git a/packages/mask/src/plugins/RedPacket/SNSAdaptor/RedPacketNftShare.tsx b/packages/mask/src/plugins/RedPacket/SNSAdaptor/RedPacketNftShare.tsx index 58cec1c5cf91..4afea0220ecd 100644 --- a/packages/mask/src/plugins/RedPacket/SNSAdaptor/RedPacketNftShare.tsx +++ b/packages/mask/src/plugins/RedPacket/SNSAdaptor/RedPacketNftShare.tsx @@ -1,6 +1,6 @@ import { makeStyles } from '@masknet/theme' import { Button, DialogActions, DialogContent } from '@mui/material' -import { InjectedDialog } from '../../../components/shared/InjectedDialog' +import { InjectedDialog } from '@masknet/shared' import { useI18N } from '../../../utils' const useStyles = makeStyles()((theme) => ({ diff --git a/packages/mask/src/plugins/RedPacket/SNSAdaptor/RedpacketNftConfirmDialog.tsx b/packages/mask/src/plugins/RedPacket/SNSAdaptor/RedpacketNftConfirmDialog.tsx index 0c7b53582212..cd7890b3b85f 100644 --- a/packages/mask/src/plugins/RedPacket/SNSAdaptor/RedpacketNftConfirmDialog.tsx +++ b/packages/mask/src/plugins/RedPacket/SNSAdaptor/RedpacketNftConfirmDialog.tsx @@ -13,10 +13,9 @@ import { isNativeTokenAddress, formatNFT_TokenId, } from '@masknet/web3-shared-evm' -import { NFTCardStyledAssetPlayer } from '@masknet/shared' +import { InjectedDialog, NFTCardStyledAssetPlayer } from '@masknet/shared' import { useRemoteControlledDialog } from '@masknet/shared-base-ui' import classNames from 'classnames' -import { InjectedDialog } from '../../../components/shared/InjectedDialog' import { Button, Grid, Link, Typography, DialogContent, List, ListItem } from '@mui/material' import ActionButton from '../../../extension/options-page/DashboardComponents/ActionButton' import { EthereumWalletConnectedBoundary } from '../../../web3/UI/EthereumWalletConnectedBoundary' diff --git a/packages/mask/src/plugins/RedPacket/SNSAdaptor/SelectNftTokenDialog.tsx b/packages/mask/src/plugins/RedPacket/SNSAdaptor/SelectNftTokenDialog.tsx index 21a3ac584938..5a7c8435cfa0 100644 --- a/packages/mask/src/plugins/RedPacket/SNSAdaptor/SelectNftTokenDialog.tsx +++ b/packages/mask/src/plugins/RedPacket/SNSAdaptor/SelectNftTokenDialog.tsx @@ -1,5 +1,5 @@ import classNames from 'classnames' -import { InjectedDialog } from '../../../components/shared/InjectedDialog' +import { InjectedDialog, NFTCardStyledAssetPlayer } from '@masknet/shared' import { ERC721TokenDetailed, ERC721ContractDetailed, @@ -17,7 +17,6 @@ import { SearchIcon } from '@masknet/icons' import CheckIcon from '@mui/icons-material/Check' import { Trans } from 'react-i18next' import { useUpdate } from 'react-use' -import { NFTCardStyledAssetPlayer } from '@masknet/shared' import { findLastIndex } from 'lodash-unified' import { NFT_RED_PACKET_MAX_SHARES } from '../constants' diff --git a/packages/mask/src/plugins/Savings/SNSAdaptor/SavingsDialog.tsx b/packages/mask/src/plugins/Savings/SNSAdaptor/SavingsDialog.tsx index 5c58a480a562..81c9d8a89829 100644 --- a/packages/mask/src/plugins/Savings/SNSAdaptor/SavingsDialog.tsx +++ b/packages/mask/src/plugins/Savings/SNSAdaptor/SavingsDialog.tsx @@ -4,7 +4,7 @@ import { Typography, DialogContent } from '@mui/material' import { ChainId, getChainIdFromNetworkType, useChainId } from '@masknet/web3-shared-evm' import { isDashboardPage, EMPTY_LIST } from '@masknet/shared-base' import { useI18N } from '../../../utils' -import { InjectedDialog } from '../../../components/shared/InjectedDialog' +import { InjectedDialog } from '@masknet/shared' import { WalletStatusBox } from '../../../components/shared/WalletStatusBox' import { AllProviderTradeContext } from '../../Trader/trader/useAllProviderTradeContext' import { TargetChainIdContext } from '../../Trader/trader/useTargetChainIdContext' diff --git a/packages/mask/src/plugins/Snapshot/SNSAdaptor/VoteConfirmDialog.tsx b/packages/mask/src/plugins/Snapshot/SNSAdaptor/VoteConfirmDialog.tsx index fd09775e3b8f..54ab254ce7a0 100644 --- a/packages/mask/src/plugins/Snapshot/SNSAdaptor/VoteConfirmDialog.tsx +++ b/packages/mask/src/plugins/Snapshot/SNSAdaptor/VoteConfirmDialog.tsx @@ -14,7 +14,7 @@ import millify from 'millify' import OpenInNew from '@mui/icons-material/OpenInNew' import { resolveBlockLinkOnExplorer, ChainId } from '@masknet/web3-shared-evm' import { useI18N } from '../../../utils' -import { InjectedDialog } from '../../../components/shared/InjectedDialog' +import { InjectedDialog } from '@masknet/shared' import { InfoField } from './InformationCard' import { EthereumWalletConnectedBoundary } from '../../../web3/UI/EthereumWalletConnectedBoundary' diff --git a/packages/mask/src/plugins/Trader/SNSAdaptor/trader/ConfirmDialog.tsx b/packages/mask/src/plugins/Trader/SNSAdaptor/trader/ConfirmDialog.tsx index d96df5edf97c..b66e38e1452c 100644 --- a/packages/mask/src/plugins/Trader/SNSAdaptor/trader/ConfirmDialog.tsx +++ b/packages/mask/src/plugins/Trader/SNSAdaptor/trader/ConfirmDialog.tsx @@ -3,9 +3,9 @@ import { ExternalLink } from 'react-feather' import BigNumber from 'bignumber.js' import { Alert, Box, Button, DialogActions, DialogContent, Link, Typography } from '@mui/material' import { makeStyles, MaskColorVar, useStylesExtends } from '@masknet/theme' -import { FormattedAddress, FormattedBalance, TokenIcon } from '@masknet/shared' +import { useValueRef } from '@masknet/shared-base-ui' +import { InjectedDialog, FormattedAddress, FormattedBalance, TokenIcon } from '@masknet/shared' import type { TradeComputed } from '../../types' -import { InjectedDialog } from '../../../../components/shared/InjectedDialog' import type { FungibleTokenDetailed, Wallet } from '@masknet/web3-shared-evm' import { createNativeToken, @@ -19,7 +19,6 @@ import { useI18N } from '../../../../utils' import { InfoIcon, RetweetIcon, CramIcon } from '@masknet/icons' import { isZero, multipliedBy } from '@masknet/web3-shared-base' import { isDashboardPage } from '@masknet/shared-base' -import { useValueRef } from '@masknet/shared-base-ui' import { TargetChainIdContext } from '../../trader/useTargetChainIdContext' import { currentSlippageSettings } from '../../settings' import { useNativeTokenPrice } from '../../../Wallet/hooks/useTokenPrice' diff --git a/packages/mask/src/plugins/Trader/SNSAdaptor/trader/SettingsDialog.tsx b/packages/mask/src/plugins/Trader/SNSAdaptor/trader/SettingsDialog.tsx index 919cd78c7776..95d5176f9000 100644 --- a/packages/mask/src/plugins/Trader/SNSAdaptor/trader/SettingsDialog.tsx +++ b/packages/mask/src/plugins/Trader/SNSAdaptor/trader/SettingsDialog.tsx @@ -1,11 +1,11 @@ import { useState, useCallback, useEffect } from 'react' import { Accordion, AccordionDetails, AccordionSummary, Alert, DialogContent, Typography } from '@mui/material' import { makeStyles, MaskColorVar, useStylesExtends } from '@masknet/theme' +import { InjectedDialog } from '@masknet/shared' import { useValueRef, useRemoteControlledDialog } from '@masknet/shared-base-ui' import { useI18N } from '../../../../utils' import { SlippageSlider } from './SlippageSlider' import { currentSlippageSettings } from '../../settings' -import { InjectedDialog } from '../../../../components/shared/InjectedDialog' import { PluginTraderMessages } from '../../messages' import { ExpandMore } from '@mui/icons-material' import { Gas1559Settings } from './Gas1559Settings' diff --git a/packages/mask/src/plugins/Trader/SNSAdaptor/trader/Trader.tsx b/packages/mask/src/plugins/Trader/SNSAdaptor/trader/Trader.tsx index c3accaad1d32..0e19cbd6c91e 100644 --- a/packages/mask/src/plugins/Trader/SNSAdaptor/trader/Trader.tsx +++ b/packages/mask/src/plugins/Trader/SNSAdaptor/trader/Trader.tsx @@ -17,6 +17,7 @@ import { UST, } from '@masknet/web3-shared-evm' import { useRemoteControlledDialog } from '@masknet/shared-base-ui' +import { usePickToken } from '@masknet/shared' import { delay } from '@dimensiondev/kit' import { useGasConfig } from './hooks/useGasConfig' import type { Coin } from '../../types' @@ -24,7 +25,7 @@ import { TokenPanelType, TradeInfo } from '../../types' import { useI18N } from '../../../../utils' import { TradeForm } from './TradeForm' import { AllProviderTradeActionType, AllProviderTradeContext } from '../../trader/useAllProviderTradeContext' -import { SelectTokenDialogEvent, WalletMessages } from '@masknet/plugin-wallet' +import { WalletMessages } from '@masknet/plugin-wallet' import { useUnmount, useUpdateEffect } from 'react-use' import { isTwitter } from '../../../../social-network-adaptor/twitter.com/base' import { activatedSocialNetworkUI } from '../../../../social-network' @@ -204,43 +205,24 @@ export function Trader(props: TraderProps) { // #region select token const excludeTokens = [inputToken, outputToken].filter(Boolean).map((x) => x?.address) as string[] - const [focusedTokenPanelType, setFocusedTokenPanelType] = useState(TokenPanelType.Input) - const { setDialog: setSelectTokenDialog } = useRemoteControlledDialog( - WalletMessages.events.selectTokenDialogUpdated, - useCallback( - (ev: SelectTokenDialogEvent) => { - if (ev.open || !ev.token || ev.uuid !== String(focusedTokenPanelType)) return + const pickToken = usePickToken() + const onTokenChipClick = useCallback( + async (panelType: TokenPanelType) => { + const picked = await pickToken({ + chainId, + disableNativeToken: false, + selectedTokens: excludeTokens, + }) + if (picked) { dispatchTradeStore({ type: - focusedTokenPanelType === TokenPanelType.Input + panelType === TokenPanelType.Input ? AllProviderTradeActionType.UPDATE_INPUT_TOKEN : AllProviderTradeActionType.UPDATE_OUTPUT_TOKEN, - token: ev.token, + token: picked, }) - if (focusedTokenPanelType === TokenPanelType.Input) { - dispatchTradeStore({ - type: AllProviderTradeActionType.UPDATE_INPUT_AMOUNT, - amount: '', - }) - } - }, - [dispatchTradeStore, focusedTokenPanelType], - ), - ) - - const onTokenChipClick = useCallback( - (type: TokenPanelType) => { - setFocusedTokenPanelType(type) - setSelectTokenDialog({ - chainId, - open: true, - uuid: String(type), - disableNativeToken: false, - FungibleTokenListProps: { - selectedTokens: excludeTokens, - }, - }) + } }, [excludeTokens.join(), chainId], ) diff --git a/packages/mask/src/plugins/Trader/SNSAdaptor/trader/TraderDialog.tsx b/packages/mask/src/plugins/Trader/SNSAdaptor/trader/TraderDialog.tsx index b8bc3821cdd8..e3ee9f2853f4 100644 --- a/packages/mask/src/plugins/Trader/SNSAdaptor/trader/TraderDialog.tsx +++ b/packages/mask/src/plugins/Trader/SNSAdaptor/trader/TraderDialog.tsx @@ -2,8 +2,8 @@ import { useEffect, useState } from 'react' import { useCurrentWeb3NetworkPluginID, useActivatedPlugin, PluginId } from '@masknet/plugin-infra' import { ChainId, useChainId, useChainIdValid } from '@masknet/web3-shared-evm' import { DialogContent } from '@mui/material' -import { InjectedDialog } from '../../../../components/shared/InjectedDialog' import { useRemoteControlledDialog } from '@masknet/shared-base-ui' +import { InjectedDialog } from '@masknet/shared' import { AllProviderTradeContext } from '../../trader/useAllProviderTradeContext' import { TargetChainIdContext } from '../../trader/useTargetChainIdContext' import { PluginTraderMessages } from '../../messages' diff --git a/packages/mask/src/plugins/Trader/SNSAdaptor/trending/CoinMetadataTags.tsx b/packages/mask/src/plugins/Trader/SNSAdaptor/trending/CoinMetadataTags.tsx index 15addd3a130a..11577896ffa5 100644 --- a/packages/mask/src/plugins/Trader/SNSAdaptor/trending/CoinMetadataTags.tsx +++ b/packages/mask/src/plugins/Trader/SNSAdaptor/trending/CoinMetadataTags.tsx @@ -1,7 +1,7 @@ import { Chip, DialogContent } from '@mui/material' import { makeStyles } from '@masknet/theme' import { useCallback, useState } from 'react' -import { InjectedDialog } from '../../../../components/shared/InjectedDialog' +import { InjectedDialog } from '@masknet/shared' import { Linking } from './Linking' const useStyles = makeStyles()((theme) => ({ diff --git a/packages/mask/src/plugins/Trader/SNSAdaptor/trending/TrendingPopper.tsx b/packages/mask/src/plugins/Trader/SNSAdaptor/trending/TrendingPopper.tsx index 3e525596bedc..d8d7af77826e 100644 --- a/packages/mask/src/plugins/Trader/SNSAdaptor/trending/TrendingPopper.tsx +++ b/packages/mask/src/plugins/Trader/SNSAdaptor/trending/TrendingPopper.tsx @@ -27,7 +27,6 @@ export function TrendingPopper(props: TrendingPopperProps) { useRemoteControlledDialog(WalletMessages.events.transactionDialogUpdated, onFreezed) useRemoteControlledDialog(WalletMessages.events.walletStatusDialogUpdated, onFreezed) useRemoteControlledDialog(WalletMessages.events.selectProviderDialogUpdated, onFreezed) - useRemoteControlledDialog(WalletMessages.events.selectTokenDialogUpdated, onFreezed) useRemoteControlledDialog(WalletMessages.events.selectWalletDialogUpdated, onFreezed) useRemoteControlledDialog(WalletMessages.events.walletConnectQRCodeDialogUpdated, onFreezed) useRemoteControlledDialog(PluginTransakMessages.buyTokenDialogUpdated, onFreezed) diff --git a/packages/mask/src/plugins/Transak/SNSAdaptor/BuyTokenDialog.tsx b/packages/mask/src/plugins/Transak/SNSAdaptor/BuyTokenDialog.tsx index 7fb2ad26a422..945d6eb6c59f 100644 --- a/packages/mask/src/plugins/Transak/SNSAdaptor/BuyTokenDialog.tsx +++ b/packages/mask/src/plugins/Transak/SNSAdaptor/BuyTokenDialog.tsx @@ -1,9 +1,9 @@ import { useRemoteControlledDialog } from '@masknet/shared-base-ui' +import { InjectedDialog } from '@masknet/shared' import { DialogContent, IconButton } from '@mui/material' import { makeStyles, useStylesExtends } from '@masknet/theme' import CloseIcon from '@mui/icons-material/Close' import { useState } from 'react' -import { InjectedDialog } from '../../../components/shared/InjectedDialog' import { useTransakURL } from '../hooks/useTransakURL' import { PluginTransakMessages } from '../messages' diff --git a/packages/mask/src/plugins/UnlockProtocol/SNSAdaptor/SelectRecipientsUnlockDialog.tsx b/packages/mask/src/plugins/UnlockProtocol/SNSAdaptor/SelectRecipientsUnlockDialog.tsx index 2c204ced01da..ce26d0c2da63 100644 --- a/packages/mask/src/plugins/UnlockProtocol/SNSAdaptor/SelectRecipientsUnlockDialog.tsx +++ b/packages/mask/src/plugins/UnlockProtocol/SNSAdaptor/SelectRecipientsUnlockDialog.tsx @@ -1,4 +1,4 @@ -import { InjectedDialog } from '../../../components/shared/InjectedDialog' +import { InjectedDialog } from '@masknet/shared' import Fuse from 'fuse.js' import { InputBase, diff --git a/packages/mask/src/plugins/UnlockProtocol/SNSAdaptor/UnlockProtocolDialog.tsx b/packages/mask/src/plugins/UnlockProtocol/SNSAdaptor/UnlockProtocolDialog.tsx index 6f33270650f5..d395b446a59a 100644 --- a/packages/mask/src/plugins/UnlockProtocol/SNSAdaptor/UnlockProtocolDialog.tsx +++ b/packages/mask/src/plugins/UnlockProtocol/SNSAdaptor/UnlockProtocolDialog.tsx @@ -1,7 +1,7 @@ import { useAccount, useChainId } from '@masknet/web3-shared-evm' import { DialogActions, DialogContent, DialogProps, Chip, Button, InputBase } from '@mui/material' import { useEffect, useState } from 'react' -import { InjectedDialog } from '../../../components/shared/InjectedDialog' +import { InjectedDialog } from '@masknet/shared' import { useI18N } from '../../../utils' import { pluginMetaKey } from '../constants' import type { UnlockLocks } from '../types' diff --git a/packages/mask/src/plugins/Wallet/Dashboard/index.tsx b/packages/mask/src/plugins/Wallet/Dashboard/index.tsx index 9a70a55c4cc2..780608eec12f 100644 --- a/packages/mask/src/plugins/Wallet/Dashboard/index.tsx +++ b/packages/mask/src/plugins/Wallet/Dashboard/index.tsx @@ -1,6 +1,5 @@ import type { Plugin } from '@masknet/plugin-infra' import { base } from '@masknet/plugin-wallet' -import { SelectTokenDialog } from '../SNSAdaptor/SelectTokenDialog' import { SelectNftContractDialog } from '../SNSAdaptor/SelectNftContractDialog' import { SelectProviderDialog } from '../SNSAdaptor/SelectProviderDialog' import { SelectWalletDialog } from '../SNSAdaptor/SelectWalletDialog' @@ -23,7 +22,6 @@ const dashboard: Plugin.Dashboard.Definition = { - @@ -31,7 +29,6 @@ const dashboard: Plugin.Dashboard.Definition = { - diff --git a/packages/mask/src/plugins/Wallet/SNSAdaptor/ConnectWalletDialog/index.tsx b/packages/mask/src/plugins/Wallet/SNSAdaptor/ConnectWalletDialog/index.tsx index becd7b16a80d..866f5eae1503 100644 --- a/packages/mask/src/plugins/Wallet/SNSAdaptor/ConnectWalletDialog/index.tsx +++ b/packages/mask/src/plugins/Wallet/SNSAdaptor/ConnectWalletDialog/index.tsx @@ -13,7 +13,7 @@ import { resolveProviderName, } from '@masknet/web3-shared-evm' import { useRemoteControlledDialog } from '@masknet/shared-base-ui' -import { InjectedDialog } from '../../../../components/shared/InjectedDialog' +import { InjectedDialog } from '@masknet/shared' import { WalletMessages, WalletRPC } from '../../messages' import { ConnectionProgress } from './ConnectionProgress' import Services from '../../../../extension/service' diff --git a/packages/mask/src/plugins/Wallet/SNSAdaptor/GasSettingDialog/index.tsx b/packages/mask/src/plugins/Wallet/SNSAdaptor/GasSettingDialog/index.tsx index 783e51eba5c8..62f0ba6d1d5c 100644 --- a/packages/mask/src/plugins/Wallet/SNSAdaptor/GasSettingDialog/index.tsx +++ b/packages/mask/src/plugins/Wallet/SNSAdaptor/GasSettingDialog/index.tsx @@ -3,8 +3,8 @@ import { DialogContent } from '@mui/material' import { WalletMessages } from '@masknet/plugin-wallet' import { makeStyles } from '@masknet/theme' import { useRemoteControlledDialog } from '@masknet/shared-base-ui' +import { InjectedDialog } from '@masknet/shared' import { GasOption } from '@masknet/web3-shared-evm' -import { InjectedDialog } from '../../../../components/shared/InjectedDialog' import { useI18N } from '../../../../utils' import { GasSetting } from './GasSetting' diff --git a/packages/mask/src/plugins/Wallet/SNSAdaptor/RenameWalletDialog.tsx b/packages/mask/src/plugins/Wallet/SNSAdaptor/RenameWalletDialog.tsx index 05e5c2826060..804abf70cac7 100644 --- a/packages/mask/src/plugins/Wallet/SNSAdaptor/RenameWalletDialog.tsx +++ b/packages/mask/src/plugins/Wallet/SNSAdaptor/RenameWalletDialog.tsx @@ -3,10 +3,9 @@ import { Button, DialogContent, DialogActions, TextField } from '@mui/material' import { makeStyles } from '@masknet/theme' import type { Wallet } from '@masknet/web3-shared-evm' import { WalletMessages, WalletRPC } from '../messages' -import { InjectedDialog } from '../../../components/shared/InjectedDialog' -import { useI18N } from '../../../utils/i18n-next-ui' -import { useSnackbarCallback } from '@masknet/shared' import { useRemoteControlledDialog } from '@masknet/shared-base-ui' +import { InjectedDialog, useSnackbarCallback } from '@masknet/shared' +import { useI18N } from '../../../utils/i18n-next-ui' const useStyles = makeStyles()((theme) => ({ content: { diff --git a/packages/mask/src/plugins/Wallet/SNSAdaptor/RestoreLegacyWalletDialog/index.tsx b/packages/mask/src/plugins/Wallet/SNSAdaptor/RestoreLegacyWalletDialog/index.tsx index 5c3ef92a33fc..25d21fd38af3 100644 --- a/packages/mask/src/plugins/Wallet/SNSAdaptor/RestoreLegacyWalletDialog/index.tsx +++ b/packages/mask/src/plugins/Wallet/SNSAdaptor/RestoreLegacyWalletDialog/index.tsx @@ -1,12 +1,12 @@ import { useCallback, useEffect } from 'react' import { useAsyncRetry } from 'react-use' import { useRemoteControlledDialog } from '@masknet/shared-base-ui' +import { InjectedDialog } from '@masknet/shared' import { Box } from '@mui/system' import { makeStyles } from '@masknet/theme' import { ProviderType } from '@masknet/web3-shared-evm' import { Button, DialogContent, Typography } from '@mui/material' import { PopupRoutes } from '@masknet/shared-base' -import { InjectedDialog } from '../../../../components/shared/InjectedDialog' import { WalletMessages, WalletRPC } from '../../messages' import { useI18N } from '../../../../utils' diff --git a/packages/mask/src/plugins/Wallet/SNSAdaptor/RiskWarningDialog/index.tsx b/packages/mask/src/plugins/Wallet/SNSAdaptor/RiskWarningDialog/index.tsx index 28ff99b7d217..0c01a034f884 100644 --- a/packages/mask/src/plugins/Wallet/SNSAdaptor/RiskWarningDialog/index.tsx +++ b/packages/mask/src/plugins/Wallet/SNSAdaptor/RiskWarningDialog/index.tsx @@ -2,11 +2,11 @@ import { useCallback } from 'react' import classnames from 'classnames' import { Trans } from 'react-i18next' import { useRemoteControlledDialog } from '@masknet/shared-base-ui' +import { InjectedDialog } from '@masknet/shared' import { formatEthereumAddress, useAccount } from '@masknet/web3-shared-evm' import PriorityHighIcon from '@mui/icons-material/PriorityHigh' import { Avatar, Button, DialogActions, DialogContent, Paper, Typography } from '@mui/material' import { getMaskColor, makeStyles, useCustomSnackbar } from '@masknet/theme' -import { InjectedDialog } from '../../../../components/shared/InjectedDialog' import { useI18N, useMatchXS } from '../../../../utils' import { WalletMessages, WalletRPC } from '../../messages' import { ActionButtonPromise } from '../../../../extension/options-page/DashboardComponents/ActionButton' diff --git a/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectNftContractDialog.tsx b/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectNftContractDialog.tsx index 2572cabda523..a0fb39bda34e 100644 --- a/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectNftContractDialog.tsx +++ b/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectNftContractDialog.tsx @@ -13,10 +13,10 @@ import { useERC721ContractDetailed, useERC721Tokens, } from '@masknet/web3-shared-evm' -import { InjectedDialog } from '../../../components/shared/InjectedDialog' +import { useRemoteControlledDialog } from '@masknet/shared-base-ui' +import { InjectedDialog } from '@masknet/shared' import { WalletMessages } from '../messages' import { useI18N } from '../../../utils' -import { useRemoteControlledDialog } from '@masknet/shared-base-ui' import { EthereumAddress } from 'wallet.ts' import { SearchInput } from '../../../extension/options-page/DashboardComponents/SearchInput' import OpenInNewIcon from '@mui/icons-material/OpenInNew' diff --git a/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/index.tsx b/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/index.tsx index 76b85bb20100..f3dadd8190a5 100644 --- a/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/index.tsx +++ b/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectProviderDialog/index.tsx @@ -1,6 +1,8 @@ import { useCallback, useEffect, useState } from 'react' import { makeStyles } from '@masknet/theme' import { DialogContent } from '@mui/material' +import { useRemoteControlledDialog, useValueRef } from '@masknet/shared-base-ui' +import { InjectedDialog } from '@masknet/shared' import { getRegisteredWeb3Networks, getRegisteredWeb3Providers, @@ -10,10 +12,8 @@ import { useWeb3UI, } from '@masknet/plugin-infra' import { isDashboardPage } from '@masknet/shared-base' -import { useRemoteControlledDialog, useValueRef } from '@masknet/shared-base-ui' import { useI18N } from '../../../../utils/i18n-next-ui' import { WalletMessages } from '../../messages' -import { InjectedDialog } from '../../../../components/shared/InjectedDialog' import { hasNativeAPI, nativeAPI } from '../../../../../shared/native-rpc' import { PluginProviderRender } from './PluginProviderRender' import { pluginIDSettings } from '../../../../settings/settings' diff --git a/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectTokenDialog.tsx b/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectTokenDialog.tsx deleted file mode 100644 index 73d036761b4e..000000000000 --- a/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectTokenDialog.tsx +++ /dev/null @@ -1,126 +0,0 @@ -import { useCallback, useEffect, useState } from 'react' -import { DialogContent, Theme, useMediaQuery } from '@mui/material' -import { makeStyles, MaskColorVar, useStylesExtends } from '@masknet/theme' -import { FungibleTokenDetailed, useChainId, ChainId, useTokenConstants } from '@masknet/web3-shared-evm' -import { InjectedDialog } from '../../../components/shared/InjectedDialog' -import { WalletMessages } from '../../Wallet/messages' -import { useI18N } from '../../../utils' -import { ERC20TokenList, ERC20TokenListProps } from '@masknet/shared' -import { useRemoteControlledDialog } from '@masknet/shared-base-ui' -import { delay } from '@dimensiondev/kit' -import { MINDS_ID } from '../../../social-network-adaptor/minds.com/base' -import { activatedSocialNetworkUI } from '../../../social-network' - -interface StyleProps { - snsId: string - isDashboard: boolean -} - -const useStyles = makeStyles()((theme, { snsId, isDashboard }) => ({ - content: { - ...(snsId === MINDS_ID ? { minWidth: 552 } : {}), - padding: theme.spacing(3), - paddingTop: isDashboard ? 0 : theme.spacing(2.8), - }, - list: { - scrollbarWidth: 'none', - '&::-webkit-scrollbar': { - display: 'none', - }, - }, - placeholder: { - textAlign: 'center', - height: 288, - paddingTop: theme.spacing(14), - boxSizing: 'border-box', - }, - search: { - backgroundColor: 'transparent !important', - border: `solid 1px ${MaskColorVar.twitterBorderLine}`, - }, -})) - -export interface SelectTokenDialogProps extends withClasses {} - -export function SelectTokenDialog(props: SelectTokenDialogProps) { - const { t } = useI18N() - const isDashboard = location.href.includes('dashboard.html') - const classes = useStylesExtends( - useStyles({ snsId: activatedSocialNetworkUI.networkIdentifier, isDashboard }), - props, - ) - const chainId = useChainId() - const { NATIVE_TOKEN_ADDRESS } = useTokenConstants(chainId) - const isMdScreen = useMediaQuery((theme) => theme.breakpoints.down('md')) - - const [id, setId] = useState('') - const [targetChainId, setChainId] = useState(chainId) - const [rowSize, setRowSize] = useState(54) - - const [title, setTitle] = useState(t('plugin_wallet_select_a_token')) - const [disableNativeToken, setDisableNativeToken] = useState(true) - const [disableSearchBar, setDisableSearchBar] = useState(false) - const [FungibleTokenListProps, setFungibleTokenListProps] = useState(null) - - useEffect(() => { - try { - const fontSize = Number.parseFloat(getComputedStyle(document.documentElement).fontSize) - setRowSize(fontSize * 4) - } catch { - setRowSize(60) - } - }, []) - - const { open, setDialog } = useRemoteControlledDialog(WalletMessages.events.selectTokenDialogUpdated, (ev) => { - if (!ev.open) return - setTitle(ev.title ?? t('plugin_wallet_select_a_token')) - setId(ev.uuid) - setDisableNativeToken(ev.disableNativeToken ?? true) - setDisableSearchBar(ev.disableSearchBar ?? false) - setFungibleTokenListProps(ev.FungibleTokenListProps ?? null) - setChainId(ev.chainId ?? undefined) - }) - const onSubmit = useCallback( - async (token: FungibleTokenDetailed) => { - setDialog({ - open: false, - uuid: id, - token, - }) - await delay(300) - }, - [id, setDialog], - ) - const onClose = useCallback(async () => { - setDialog({ - open: false, - uuid: id, - }) - await delay(300) - }, [id, setDialog]) - - return ( - - - - - - ) -} diff --git a/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectWalletDialog.tsx b/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectWalletDialog.tsx index c661e2bc02d9..c02c08b27c72 100644 --- a/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectWalletDialog.tsx +++ b/packages/mask/src/plugins/Wallet/SNSAdaptor/SelectWalletDialog.tsx @@ -3,12 +3,12 @@ import { Button, DialogActions, DialogContent } from '@mui/material' import { makeStyles, useStylesExtends } from '@masknet/theme' import { ProviderType, useWallets, useWallet, NetworkType } from '@masknet/web3-shared-evm' import { useRemoteControlledDialog } from '@masknet/shared-base-ui' +import { InjectedDialog } from '@masknet/shared' import { DashboardRoutes } from '@masknet/shared-base' import { useI18N } from '../../../utils' import { WalletMessages, WalletRPC } from '../messages' import { WalletInList } from '../../../components/shared/SelectWallet/WalletInList' import Services from '../../../extension/service' -import { InjectedDialog } from '../../../components/shared/InjectedDialog' import { delay } from '@dimensiondev/kit' const useStyles = makeStyles()({ diff --git a/packages/mask/src/plugins/Wallet/SNSAdaptor/TransactionDialog.tsx b/packages/mask/src/plugins/Wallet/SNSAdaptor/TransactionDialog.tsx index 3d0d3a010904..4e819e6cdac7 100644 --- a/packages/mask/src/plugins/Wallet/SNSAdaptor/TransactionDialog.tsx +++ b/packages/mask/src/plugins/Wallet/SNSAdaptor/TransactionDialog.tsx @@ -9,9 +9,9 @@ import { TransactionStateType, resolveTransactionLinkOnExplorer, } from '@masknet/web3-shared-evm' -import { useI18N } from '../../../utils' import { useRemoteControlledDialog } from '@masknet/shared-base-ui' -import { InjectedDialog } from '../../../components/shared/InjectedDialog' +import { InjectedDialog } from '@masknet/shared' +import { useI18N } from '../../../utils' import { WalletMessages } from '../messages' import { activatedSocialNetworkUI } from '../../../social-network' diff --git a/packages/mask/src/plugins/Wallet/SNSAdaptor/WalletConnectQRCodeDialog/index.tsx b/packages/mask/src/plugins/Wallet/SNSAdaptor/WalletConnectQRCodeDialog/index.tsx index f84c6c711972..7de9b3a09cc9 100644 --- a/packages/mask/src/plugins/Wallet/SNSAdaptor/WalletConnectQRCodeDialog/index.tsx +++ b/packages/mask/src/plugins/Wallet/SNSAdaptor/WalletConnectQRCodeDialog/index.tsx @@ -1,11 +1,11 @@ import { useState } from 'react' import { Button, DialogActions, DialogContent } from '@mui/material' import { makeStyles } from '@masknet/theme' -import { useI18N } from '../../../../utils' import { useRemoteControlledDialog } from '@masknet/shared-base-ui' +import { InjectedDialog } from '@masknet/shared' +import { useI18N } from '../../../../utils' import { WalletMessages } from '../../messages' import Services from '../../../../extension/service' -import { InjectedDialog } from '../../../../components/shared/InjectedDialog' import { SafariPlatform } from './SafariPlatform' import { FirefoxPlatform } from './FirefoxPlatform' import { QRCodeModel } from './QRCodeModel' diff --git a/packages/mask/src/plugins/Wallet/SNSAdaptor/WalletStatusDialog/index.tsx b/packages/mask/src/plugins/Wallet/SNSAdaptor/WalletStatusDialog/index.tsx index e228a5248a86..2e2400361dbb 100644 --- a/packages/mask/src/plugins/Wallet/SNSAdaptor/WalletStatusDialog/index.tsx +++ b/packages/mask/src/plugins/Wallet/SNSAdaptor/WalletStatusDialog/index.tsx @@ -2,10 +2,10 @@ import { useCallback } from 'react' import { DialogActions, DialogContent, Typography } from '@mui/material' import ErrorIcon from '@mui/icons-material/Error' import { useRemoteControlledDialog } from '@masknet/shared-base-ui' +import { InjectedDialog } from '@masknet/shared' import { CrossIsolationMessages } from '@masknet/shared-base' import { useChainIdValid } from '@masknet/web3-shared-evm' import { makeStyles } from '@masknet/theme' -import { InjectedDialog } from '../../../../components/shared/InjectedDialog' import { WalletStatusBox } from '../../../../components/shared/WalletStatusBox' import { useI18N } from '../../../../utils' import { WalletMessages } from '../../messages' diff --git a/packages/mask/src/plugins/Wallet/SNSAdaptor/index.tsx b/packages/mask/src/plugins/Wallet/SNSAdaptor/index.tsx index 954cdf2aa90f..25751a58a88b 100644 --- a/packages/mask/src/plugins/Wallet/SNSAdaptor/index.tsx +++ b/packages/mask/src/plugins/Wallet/SNSAdaptor/index.tsx @@ -1,6 +1,5 @@ import type { Plugin } from '@masknet/plugin-infra' import { base } from '@masknet/plugin-wallet' -import { SelectTokenDialog } from './SelectTokenDialog' import { SelectNftContractDialog } from './SelectNftContractDialog' import { SelectProviderDialog } from './SelectProviderDialog' import { SelectWalletDialog } from './SelectWalletDialog' @@ -23,7 +22,6 @@ const sns: Plugin.SNSAdaptor.Definition = { - diff --git a/packages/mask/src/plugins/Wallet/messages.ts b/packages/mask/src/plugins/Wallet/messages.ts index ff23a6a24d43..3d03a916363a 100644 --- a/packages/mask/src/plugins/Wallet/messages.ts +++ b/packages/mask/src/plugins/Wallet/messages.ts @@ -3,7 +3,7 @@ import { PLUGIN_ID, WalletMessages } from '@masknet/plugin-wallet' import type { _AsyncVersionOf } from 'async-call-rpc' export { WalletMessages } from '@masknet/plugin-wallet' -export type { SelectTokenDialogEvent, SelectNftContractDialogEvent } from '@masknet/plugin-wallet' +export type { SelectNftContractDialogEvent } from '@masknet/plugin-wallet' export const WalletRPC: _AsyncVersionOf = createPluginRPC( PLUGIN_ID, () => import('./services') as any, diff --git a/packages/mask/src/plugins/dHEDGE/UI/InvestDialog.tsx b/packages/mask/src/plugins/dHEDGE/UI/InvestDialog.tsx index 96e30a9465bd..88cf755db47f 100644 --- a/packages/mask/src/plugins/dHEDGE/UI/InvestDialog.tsx +++ b/packages/mask/src/plugins/dHEDGE/UI/InvestDialog.tsx @@ -1,3 +1,7 @@ +import { useRemoteControlledDialog } from '@masknet/shared-base-ui' +import { usePickToken, InjectedDialog } from '@masknet/shared' +import { makeStyles } from '@masknet/theme' +import { isZero, rightShift } from '@masknet/web3-shared-base' import { EthereumTokenType, formatBalance, @@ -6,24 +10,20 @@ import { useAccount, useFungibleTokenBalance, } from '@masknet/web3-shared-evm' -import { isZero, rightShift } from '@masknet/web3-shared-base' import { DialogContent } from '@mui/material' -import { makeStyles } from '@masknet/theme' import { useCallback, useEffect, useMemo, useState } from 'react' import { v4 as uuid } from 'uuid' -import { InjectedDialog } from '../../../components/shared/InjectedDialog' import ActionButton from '../../../extension/options-page/DashboardComponents/ActionButton' import { activatedSocialNetworkUI } from '../../../social-network' -import { isTwitter } from '../../../social-network-adaptor/twitter.com/base' import { isFacebook } from '../../../social-network-adaptor/facebook.com/base' -import { useRemoteControlledDialog } from '@masknet/shared-base-ui' +import { isTwitter } from '../../../social-network-adaptor/twitter.com/base' import { useI18N } from '../../../utils/i18n-next-ui' import { EthereumERC20TokenApprovedBoundary } from '../../../web3/UI/EthereumERC20TokenApprovedBoundary' import { EthereumWalletConnectedBoundary } from '../../../web3/UI/EthereumWalletConnectedBoundary' import { TokenAmountPanel } from '../../../web3/UI/TokenAmountPanel' import { PluginTraderMessages } from '../../Trader/messages' import type { Coin } from '../../Trader/types' -import { SelectTokenDialogEvent, WalletMessages } from '../../Wallet/messages' +import { WalletMessages } from '../../Wallet/messages' import { useInvestCallback } from '../hooks/useInvestCallback' import { PluginDHedgeMessages } from '../messages' import type { Pool } from '../types' @@ -54,7 +54,7 @@ const useStyles = makeStyles()((theme) => ({ export function InvestDialog() { const { t } = useI18N() const { classes } = useStyles() - const [id] = useState(uuid()) + const [id] = useState(uuid) const [pool, setPool] = useState() const [token, setToken] = useState() const [allowedTokens, setAllowedTokens] = useState() @@ -77,26 +77,14 @@ export function InvestDialog() { // #endregion // #region select token - const { setDialog: setSelectTokenDialogOpen } = useRemoteControlledDialog( - WalletMessages.events.selectTokenDialogUpdated, - useCallback( - (ev: SelectTokenDialogEvent) => { - if (ev.open || !ev.token || ev.uuid !== id) return - setToken(ev.token) - }, - [id], - ), - ) - const onSelectTokenChipClick = useCallback(() => { - setSelectTokenDialogOpen({ - open: true, - uuid: id, + const pickToken = usePickToken() + const onSelectTokenChipClick = useCallback(async () => { + const picked = await pickToken({ disableNativeToken: true, - FungibleTokenListProps: { - whitelist: allowedTokens, - }, + whitelist: allowedTokens, }) - }, [id, token?.address, allowedTokens]) + if (picked) setToken(picked) + }, [pickToken, token?.address, allowedTokens]) // #endregion // #region amount diff --git a/packages/mask/src/social-network-adaptor/facebook.com/ui-provider.ts b/packages/mask/src/social-network-adaptor/facebook.com/ui-provider.ts index f10fb500ca71..842709e8305c 100644 --- a/packages/mask/src/social-network-adaptor/facebook.com/ui-provider.ts +++ b/packages/mask/src/social-network-adaptor/facebook.com/ui-provider.ts @@ -146,10 +146,12 @@ const facebookUI: SocialNetworkUI.Definition = { }, customization: { paletteMode: PaletteModeProviderFacebook, - componentOverwrite: { + sharedComponentOverwrite: { InjectedDialog: { classes: useInjectedDialogClassesOverwriteFacebook, }, + }, + componentOverwrite: { RenderFragments: FacebookRenderFragments, }, useTheme: useThemeFacebookVariant, diff --git a/packages/mask/src/social-network-adaptor/instagram.com/base.ts b/packages/mask/src/social-network-adaptor/instagram.com/base.ts index 54bbad8276e2..3135f0cde0c2 100644 --- a/packages/mask/src/social-network-adaptor/instagram.com/base.ts +++ b/packages/mask/src/social-network-adaptor/instagram.com/base.ts @@ -1,17 +1,17 @@ +import { INSTAGRAM_ID } from '@masknet/shared' import { SocialNetworkEnum } from '@masknet/encryption' import type { SocialNetwork, SocialNetworkWorker } from '../../social-network/types' -const id = 'instagram.com' const origins = ['https://www.instagram.com/*', 'https://m.instagram.com/*', 'https://instagram.com/*'] export const instagramBase: SocialNetwork.Base = { - networkIdentifier: id, + networkIdentifier: INSTAGRAM_ID, encryptionNetwork: SocialNetworkEnum.Instagram, declarativePermissions: { origins }, shouldActivate(location) { - return location.host.endsWith(id) + return location.host.endsWith(INSTAGRAM_ID) }, } export const instagramWorkerBase: SocialNetworkWorker.WorkerBase & SocialNetwork.Base = { ...instagramBase, - gunNetworkHint: id, + gunNetworkHint: INSTAGRAM_ID, } diff --git a/packages/mask/src/social-network-adaptor/instagram.com/injection/NFT/NFTAvatarSettingDialog.tsx b/packages/mask/src/social-network-adaptor/instagram.com/injection/NFT/NFTAvatarSettingDialog.tsx index 3442a7af4232..3f350a513860 100644 --- a/packages/mask/src/social-network-adaptor/instagram.com/injection/NFT/NFTAvatarSettingDialog.tsx +++ b/packages/mask/src/social-network-adaptor/instagram.com/injection/NFT/NFTAvatarSettingDialog.tsx @@ -4,7 +4,7 @@ import { useCurrentVisitingIdentity } from '../../../../components/DataSource/us import { toPNG } from '../../../../plugins/Avatar/utils' import { useMount } from 'react-use' import { getAvatarId } from '../../utils/user' -import { InjectedDialog } from '../../../../components/shared/InjectedDialog' +import { InjectedDialog } from '@masknet/shared' import { DialogContent } from '@mui/material' import { NFTAvatar } from '../../../../plugins/Avatar/SNSAdaptor/NFTAvatar' import { DialogStackingProvider, makeStyles } from '@masknet/theme' diff --git a/packages/mask/src/social-network-adaptor/minds.com/base.ts b/packages/mask/src/social-network-adaptor/minds.com/base.ts index e827f3b6372b..33027b5eb400 100644 --- a/packages/mask/src/social-network-adaptor/minds.com/base.ts +++ b/packages/mask/src/social-network-adaptor/minds.com/base.ts @@ -1,7 +1,7 @@ +import { MINDS_ID } from '@masknet/shared' import { SocialNetworkEnum } from '@masknet/encryption' import type { SocialNetwork, SocialNetworkWorker } from '../../social-network/types' -export const MINDS_ID = 'minds.com' const origins = ['https://www.minds.com/*', 'https://minds.com/*', 'https://cdn.minds.com/*'] export const mindsBase: SocialNetwork.Base = { networkIdentifier: MINDS_ID, diff --git a/packages/mask/src/social-network-adaptor/minds.com/ui-provider.ts b/packages/mask/src/social-network-adaptor/minds.com/ui-provider.ts index db2f22d589ae..1c0bbfb1941d 100644 --- a/packages/mask/src/social-network-adaptor/minds.com/ui-provider.ts +++ b/packages/mask/src/social-network-adaptor/minds.com/ui-provider.ts @@ -125,10 +125,12 @@ const mindsUI: SocialNetworkUI.Definition = { }, customization: { paletteMode: PaletteModeProviderMinds, - componentOverwrite: { + sharedComponentOverwrite: { InjectedDialog: { classes: useInjectedDialogClassesOverwriteMinds, }, + }, + componentOverwrite: { RenderFragments: MindsRenderFragments, }, useTheme: useThemeMindsVariant, diff --git a/packages/mask/src/social-network-adaptor/opensea.io/base.ts b/packages/mask/src/social-network-adaptor/opensea.io/base.ts index 6757cb5464da..4e32a6a4a87b 100644 --- a/packages/mask/src/social-network-adaptor/opensea.io/base.ts +++ b/packages/mask/src/social-network-adaptor/opensea.io/base.ts @@ -1,7 +1,7 @@ +import { OPENSEA_ID } from '@masknet/shared' import { SocialNetworkEnum } from '@masknet/encryption' import type { SocialNetwork, SocialNetworkWorker } from '../../social-network/types' -const OPENSEA_ID = 'opensea.io' const origins = ['https://opensea.io/*'] export const openseaBase: SocialNetwork.Base = { networkIdentifier: OPENSEA_ID, diff --git a/packages/mask/src/social-network-adaptor/twitter.com/base.ts b/packages/mask/src/social-network-adaptor/twitter.com/base.ts index 6f6a912ac250..a90412694e6f 100644 --- a/packages/mask/src/social-network-adaptor/twitter.com/base.ts +++ b/packages/mask/src/social-network-adaptor/twitter.com/base.ts @@ -1,10 +1,10 @@ +import { TWITTER_ID } from '@masknet/shared' import { SocialNetworkEnum } from '@masknet/encryption' import type { SocialNetwork, SocialNetworkWorker } from '../../social-network/types' -const id = 'twitter.com' const origins = ['https://mobile.twitter.com/*', 'https://twitter.com/*'] export const twitterBase: SocialNetwork.Base = { - networkIdentifier: id, + networkIdentifier: TWITTER_ID, encryptionNetwork: SocialNetworkEnum.Twitter, declarativePermissions: { origins }, shouldActivate(location) { @@ -13,7 +13,7 @@ export const twitterBase: SocialNetwork.Base = { } export function isTwitter(ui: SocialNetwork.Base) { - return ui.networkIdentifier === id + return ui.networkIdentifier === TWITTER_ID } export const twitterWorkerBase: SocialNetworkWorker.WorkerBase & SocialNetwork.Base = { diff --git a/packages/mask/src/social-network-adaptor/twitter.com/ui-provider.ts b/packages/mask/src/social-network-adaptor/twitter.com/ui-provider.ts index ad5d4536c559..872aed50431c 100644 --- a/packages/mask/src/social-network-adaptor/twitter.com/ui-provider.ts +++ b/packages/mask/src/social-network-adaptor/twitter.com/ui-provider.ts @@ -134,10 +134,12 @@ const twitterUI: SocialNetworkUI.Definition = { }, customization: { paletteMode: PaletteModeProviderTwitter, - componentOverwrite: { + sharedComponentOverwrite: { InjectedDialog: { classes: useInjectedDialogClassesOverwriteTwitter, }, + }, + componentOverwrite: { RenderFragments: TwitterRenderFragments, }, useTheme: useThemeTwitterVariant, diff --git a/packages/mask/src/social-network/types.ts b/packages/mask/src/social-network/types.ts index 09ea52e4fb6b..5601bec36c8b 100644 --- a/packages/mask/src/social-network/types.ts +++ b/packages/mask/src/social-network/types.ts @@ -11,13 +11,12 @@ import type { } from '@masknet/shared-base' import type { SerializableTypedMessages } from '@masknet/typed-message' import type { RenderFragmentsContextType } from '@masknet/typed-message/dom' +import type { SharedComponentOverwrite } from '@masknet/shared' import type { PaletteMode, Theme } from '@mui/material' import type { Subscription } from 'use-subscription' -import type { InjectedDialogClassKey, InjectedDialogProps } from '../components/shared/InjectedDialog' import type { Profile } from '../database' import type { createSNSAdaptorSpecializedPostContext } from './utils/create-post-context' -type ClassNameMap = { [P in ClassKey]: string } // Don't define values in namespaces export namespace SocialNetwork { export interface PayloadEncoding { @@ -270,6 +269,7 @@ export namespace SocialNetworkUI { /** Provide the ability to detect the current color scheme (light or dark) in the current SNS */ paletteMode?: PaletteModeProvider i18nOverwrite?: I18NOverwrite + sharedComponentOverwrite?: SharedComponentOverwrite componentOverwrite?: ComponentOverwrite } export interface PaletteModeProvider { @@ -277,13 +277,8 @@ export namespace SocialNetworkUI { start(signal: AbortSignal): void } export interface ComponentOverwrite { - InjectedDialog?: ComponentOverwriteConfig RenderFragments?: RenderFragmentsContextType } - export interface ComponentOverwriteConfig { - classes?: () => { classes: Partial> } - props?: (props: Props) => Props - } export interface I18NOverwrite { [namespace: string]: I18NOverwriteNamespace } diff --git a/packages/mask/src/social-network/ui.ts b/packages/mask/src/social-network/ui.ts index a83e52c5f38d..4c29d701ee16 100644 --- a/packages/mask/src/social-network/ui.ts +++ b/packages/mask/src/social-network/ui.ts @@ -21,6 +21,7 @@ import { createPluginHost } from '../plugin-infra/host' import { definedSocialNetworkUIs } from './define' import { setupShadowRootPortal, MaskMessages } from '../utils' import { delay, waitDocumentReadyState } from '@dimensiondev/kit' +import { sharedUINetworkIdentifier, sharedUIComponentOverwrite } from '@masknet/shared' import { SocialNetworkEnum } from '@masknet/encryption' const definedSocialNetworkUIsResolved = new Map() @@ -51,6 +52,12 @@ export async function activateSocialNetworkUIInner(ui_deferred: SocialNetworkUI. console.log('Activating provider', ui_deferred.networkIdentifier) const ui = (activatedSocialNetworkUI = await loadSocialNetworkUI(ui_deferred.networkIdentifier)) + + sharedUINetworkIdentifier.value = ui_deferred.networkIdentifier + if (ui.customization.sharedComponentOverwrite) { + sharedUIComponentOverwrite.value = ui.customization.sharedComponentOverwrite + } + console.log('Provider activated. You can access it by globalThis.ui', ui) Object.assign(globalThis, { ui }) diff --git a/packages/mask/src/social-network/utils/create-post-context.ts b/packages/mask/src/social-network/utils/create-post-context.ts index ed34f3e81432..bc1c175702ff 100644 --- a/packages/mask/src/social-network/utils/create-post-context.ts +++ b/packages/mask/src/social-network/utils/create-post-context.ts @@ -22,7 +22,7 @@ import { } from '@masknet/shared-base' import { Err, Result } from 'ts-results' import type { Subscription } from 'use-subscription' -import { activatedSocialNetworkUI } from '../' +import { activatedSocialNetworkUI } from '../ui' import { resolveFacebookLink } from '../../social-network-adaptor/facebook.com/utils/resolveFacebookLink' import type { SupportedPayloadVersions } from '@masknet/encryption' diff --git a/packages/mask/src/tsconfig.json b/packages/mask/src/tsconfig.json index 40b24ac85751..eb5b6ba34de4 100644 --- a/packages/mask/src/tsconfig.json +++ b/packages/mask/src/tsconfig.json @@ -23,6 +23,7 @@ { "path": "../../web3-shared/base" }, { "path": "../../web3-shared/evm" }, { "path": "../../web3-shared/flow" }, + { "path": "../../web3-shared/solana" }, { "path": "../../web3-providers" }, { "path": "../../theme" }, { "path": "../../icons" }, diff --git a/packages/mask/src/utils/shadow-root/index.ts b/packages/mask/src/utils/shadow-root/index.ts index b7f722bb05a6..046fdafecb69 100644 --- a/packages/mask/src/utils/shadow-root/index.ts +++ b/packages/mask/src/utils/shadow-root/index.ts @@ -1,6 +1 @@ export * from './renderInShadowRoot' -export { - usePortalShadowRoot, - createShadowRootForwardedComponent, - createShadowRootForwardedPopperComponent, -} from '@masknet/theme' diff --git a/packages/plugins/Wallet/src/messages.ts b/packages/plugins/Wallet/src/messages.ts index 7ae1e45c92d7..74d0ee0e1780 100644 --- a/packages/plugins/Wallet/src/messages.ts +++ b/packages/plugins/Wallet/src/messages.ts @@ -1,17 +1,16 @@ -import type BigNumber from 'bignumber.js' -import type { JsonRpcPayload } from 'web3-core-helpers' +import { createPluginMessage, PluginMessageEmitter } from '@masknet/plugin-infra' import type { - FungibleTokenDetailed, + ChainId, ERC721ContractDetailed, + GasOption, GasOptions, NetworkType, ProviderType, TransactionState, Wallet, - GasOption, - ChainId, } from '@masknet/web3-shared-evm' -import { createPluginMessage, PluginMessageEmitter } from '@masknet/plugin-infra' +import type BigNumber from 'bignumber.js' +import type { JsonRpcPayload } from 'web3-core-helpers' import { PLUGIN_ID } from './constants' export type TransactionDialogEvent = @@ -102,33 +101,6 @@ export type WalletConnectQRCodeDialogEvent = open: false } -export type SelectTokenDialogEvent = - | { - open: true - uuid: string - chainId?: ChainId - disableNativeToken?: boolean - disableSearchBar?: boolean - FungibleTokenListProps?: { - keyword?: string - whitelist?: string[] - blacklist?: string[] - tokens?: FungibleTokenDetailed[] - selectedTokens?: string[] - } - title?: string - } - | { - open: false - uuid: string - - /** - * The selected detailed token. - */ - token?: FungibleTokenDetailed - title?: string - } - export type SelectNftContractDialogEvent = { open: boolean uuid: string @@ -188,11 +160,6 @@ export interface WalletMessage { */ gasSettingDialogUpdated: GasSettingDialogEvent - /** - * Select token dialog - */ - selectTokenDialogUpdated: SelectTokenDialogEvent - /** * Select nft contract dialog */ diff --git a/packages/shared-base-ui/package.json b/packages/shared-base-ui/package.json index ebb6a6817fa0..4f623f801dd5 100644 --- a/packages/shared-base-ui/package.json +++ b/packages/shared-base-ui/package.json @@ -8,7 +8,9 @@ "@dimensiondev/holoflows-kit": "^0.9.0-20210902104757-7c3d0d0", "@masknet/shared-base": "workspace:*", "react-use": "^17.3.2", - "use-subscription": "^1.5.1", - "uuid": "^8.3.2" + "use-subscription": "^1.6.0", + "@types/use-subscription": "^1.0.0", + "uuid": "^8.3.2", + "@types/uuid": "^8.3.4" } } diff --git a/packages/shared-base-ui/src/hooks/useRemoteControlledDialog.ts b/packages/shared-base-ui/src/hooks/useRemoteControlledDialog.ts index a7ccc57e70e5..45c62225ee24 100644 --- a/packages/shared-base-ui/src/hooks/useRemoteControlledDialog.ts +++ b/packages/shared-base-ui/src/hooks/useRemoteControlledDialog.ts @@ -22,7 +22,7 @@ export function useRemoteControlledDialog( onUpdateByRemote?: (ev: T) => void, tabType: 'self' | 'activated' = 'self', ): Result { - const [HOOK_ID] = useState(uuid()) // create an uuid for every hook + const [HOOK_ID] = useState(uuid) // create an uuid for every hook const [open, setOpen] = useState(false) useEffect( diff --git a/packages/shared/package.json b/packages/shared/package.json index f2a4402709ae..2a66c2dda832 100644 --- a/packages/shared/package.json +++ b/packages/shared/package.json @@ -5,6 +5,7 @@ "dependencies": { "@dimensiondev/holoflows-kit": "^0.9.0-20210902104757-7c3d0d0", "@masknet/icons": "workspace:*", + "@masknet/shared-base-ui": "workspace:*", "@masknet/plugin-infra": "workspace:*", "@masknet/shared-base": "workspace:*", "@masknet/theme": "workspace:*", @@ -19,7 +20,6 @@ "react-feather": "^2.0.9", "react-use": "^17.3.2", "urlcat": "^2.0.4", - "use-subscription": "^1.5.1", - "uuid": "^8.3.2" + "use-subscription": "^1.6.0" } } diff --git a/packages/shared/src/constants.tsx b/packages/shared/src/constants.tsx index 839fb817c6b4..03e0e05d3d99 100644 --- a/packages/shared/src/constants.tsx +++ b/packages/shared/src/constants.tsx @@ -7,12 +7,18 @@ import { OpenSeaColoredIcon, } from '@masknet/icons' +export const MINDS_ID = 'minds.com' +export const FACEBOOK_ID = 'facebook.com' +export const TWITTER_ID = 'twitter.com' +export const INSTAGRAM_ID = 'instagram.com' +export const OPENSEA_ID = 'opensea.io' + export const SOCIAL_MEDIA_ICON_MAPPING: Record = { - 'twitter.com': , - 'facebook.com': , - 'minds.com': , - 'instagram.com': , - 'opensea.io': , + [TWITTER_ID]: , + [FACEBOOK_ID]: , + [MINDS_ID]: , + [INSTAGRAM_ID]: , + [OPENSEA_ID]: , } export const mediaViewerUrl = 'https://media-viewer.r2d2.to/index.html' diff --git a/packages/shared/src/contexts/SharedContextProvider.tsx b/packages/shared/src/contexts/SharedContextProvider.tsx new file mode 100644 index 000000000000..4191366944a1 --- /dev/null +++ b/packages/shared/src/contexts/SharedContextProvider.tsx @@ -0,0 +1,11 @@ +import type { FC } from 'react' +import { BaseSharedUIProvider } from './base' +import { EvmSharedUIProvider } from './evm' + +export const SharedContextProvider: FC = ({ children }) => { + return ( + + {children} + + ) +} diff --git a/packages/shared/src/contexts/base/BaseSharedUIProvider.tsx b/packages/shared/src/contexts/base/BaseSharedUIProvider.tsx new file mode 100644 index 000000000000..bcaee9b4979b --- /dev/null +++ b/packages/shared/src/contexts/base/BaseSharedUIProvider.tsx @@ -0,0 +1,36 @@ +import { ValueRef } from '@dimensiondev/holoflows-kit' +import { createContext, FC, useContext, useMemo } from 'react' +import { useValueRef } from '@masknet/shared-base-ui' +import type { SharedComponentOverwrite } from './types' + +export const sharedUINetworkIdentifier = new ValueRef('unknown') +export const sharedUIComponentOverwrite = new ValueRef({}) + +interface ContextOptions { + networkIdentifier: string + componentOverwrite: SharedComponentOverwrite +} + +const BaseUIContext = createContext({ + networkIdentifier: sharedUINetworkIdentifier.value, + componentOverwrite: sharedUIComponentOverwrite.value, +}) + +export const BaseSharedUIProvider: FC = ({ children }) => { + const snsId = useValueRef(sharedUINetworkIdentifier) + const overwrite = useValueRef(sharedUIComponentOverwrite) + + const contextValue = useMemo(() => { + const value: ContextOptions = { + networkIdentifier: snsId, + componentOverwrite: overwrite, + } + return value + }, [snsId, overwrite]) + + return {children} +} + +export const useBaseUIRuntime = () => { + return useContext(BaseUIContext) +} diff --git a/packages/shared/src/contexts/base/index.ts b/packages/shared/src/contexts/base/index.ts new file mode 100644 index 000000000000..3ad8144c494a --- /dev/null +++ b/packages/shared/src/contexts/base/index.ts @@ -0,0 +1,2 @@ +export * from './BaseSharedUIProvider' +export * from './types' diff --git a/packages/shared/src/contexts/base/types.ts b/packages/shared/src/contexts/base/types.ts new file mode 100644 index 000000000000..04c1876e526a --- /dev/null +++ b/packages/shared/src/contexts/base/types.ts @@ -0,0 +1,6 @@ +import type { ComponentOverwriteConfig } from '@masknet/theme' +import type { InjectedDialogClassKey, InjectedDialogProps } from '../components' + +export interface SharedComponentOverwrite { + InjectedDialog?: ComponentOverwriteConfig +} diff --git a/packages/shared/src/contexts/components/DialogDismissIcon.tsx b/packages/shared/src/contexts/components/DialogDismissIcon.tsx new file mode 100644 index 000000000000..b6b0af2ddd4c --- /dev/null +++ b/packages/shared/src/contexts/components/DialogDismissIcon.tsx @@ -0,0 +1,20 @@ +// see https://github.com/import-js/eslint-plugin-import/issues/2288 +// eslint-disable-next-line import/no-deprecated +import { useTheme, useMediaQuery } from '@mui/material' +import CloseIcon from '@mui/icons-material/Close' +import ArrowBackRoundedIcon from '@mui/icons-material/ArrowBackRounded' + +export interface DialogDismissIconUIProps { + style?: 'auto' | 'back' | 'close' +} + +export function DialogDismissIcon(props: DialogDismissIconUIProps) { + const close = + const back = + // see https://github.com/import-js/eslint-plugin-import/issues/2288 + // eslint-disable-next-line import/no-deprecated + const auto = useMediaQuery(`(min-width: ${useTheme().breakpoints.values.sm}px)`) + if (!props.style || props.style === 'auto') return auto ? close : back + if (props.style === 'back') return back + return close +} diff --git a/packages/mask/src/components/shared/InjectedDialog.tsx b/packages/shared/src/contexts/components/InjectedDialog.tsx similarity index 82% rename from packages/mask/src/components/shared/InjectedDialog.tsx rename to packages/shared/src/contexts/components/InjectedDialog.tsx index c8275949d509..9e55e3a89039 100644 --- a/packages/mask/src/components/shared/InjectedDialog.tsx +++ b/packages/shared/src/contexts/components/InjectedDialog.tsx @@ -1,5 +1,8 @@ -import { Children, cloneElement } from 'react' +import { EnhanceableSite, isDashboardPage } from '@masknet/shared-base' +import { ErrorBoundary, useValueRef } from '@masknet/shared-base-ui' +import { makeStyles, mergeClasses, useDialogStackActor, usePortalShadowRoot, useStylesExtends } from '@masknet/theme' import { + Dialog, DialogActions, DialogClassKey, DialogContent, @@ -8,22 +11,19 @@ import { DialogTitle, IconButton, Typography, - useTheme, - Dialog, useMediaQuery, + useTheme, } from '@mui/material' -import { makeStyles, useDialogStackActor, useStylesExtends, mergeClasses } from '@masknet/theme' -import { EnhanceableSite, isDashboardPage } from '@masknet/shared-base' -import { ErrorBoundary } from '@masknet/shared-base-ui' -import { useI18N, usePortalShadowRoot } from '../../utils' -import { DialogDismissIconUI } from '../InjectedComponents/DialogDismissIcon' -import { activatedSocialNetworkUI } from '../../social-network' +import { Children, cloneElement } from 'react' +import { useSharedI18N } from '../../locales' +import { sharedUIComponentOverwrite, sharedUINetworkIdentifier } from '../base' +import { DialogDismissIcon } from './DialogDismissIcon' interface StyleProps { - snsId: string + clean: boolean } -const useStyles = makeStyles()((theme, { snsId }) => ({ +const useStyles = makeStyles()((theme, { clean }) => ({ dialogTitle: { padding: theme.spacing(1, 2), borderBottom: `1px solid ${theme.palette.divider}`, @@ -38,11 +38,7 @@ const useStyles = makeStyles()((theme, { snsId }) => ({ dialogCloseButton: { color: theme.palette.text.primary, }, - paper: { - ...(snsId === EnhanceableSite.Minds || snsId === EnhanceableSite.Facebook - ? { width: 'auto', backgroundImage: 'none' } - : {}), - }, + paper: clean ? { width: 'auto', backgroundImage: 'none' } : {}, })) export type InjectedDialogClassKey = @@ -64,8 +60,10 @@ export interface InjectedDialogProps extends Omit - diff --git a/packages/shared/src/contexts/components/index.ts b/packages/shared/src/contexts/components/index.ts new file mode 100644 index 000000000000..beb73912eb49 --- /dev/null +++ b/packages/shared/src/contexts/components/index.ts @@ -0,0 +1 @@ +export * from './InjectedDialog' diff --git a/packages/shared/src/contexts/evm/TokenPicker/SelectTokenDialog.tsx b/packages/shared/src/contexts/evm/TokenPicker/SelectTokenDialog.tsx new file mode 100644 index 000000000000..37c841bc85e3 --- /dev/null +++ b/packages/shared/src/contexts/evm/TokenPicker/SelectTokenDialog.tsx @@ -0,0 +1,110 @@ +import { EMPTY_LIST } from '@masknet/shared-base' +import { ERC20TokenList, useSharedI18N } from '@masknet/shared' +import { makeStyles, MaskColorVar } from '@masknet/theme' +import { ChainId, FungibleTokenDetailed, useTokenConstants } from '@masknet/web3-shared-evm' +// see https://github.com/import-js/eslint-plugin-import/issues/2288 +// eslint-disable-next-line import/no-deprecated +import { DialogContent, Theme, useMediaQuery } from '@mui/material' +import type { FC } from 'react' +import { useBaseUIRuntime } from '../../base' +import { MINDS_ID } from '../../../constants' +import { InjectedDialog } from '../../components' +import { useRowSize } from './useRowSize' + +interface StyleProps { + compact: boolean + disablePaddingTop: boolean +} + +const useStyles = makeStyles()((theme, { compact, disablePaddingTop }) => ({ + content: { + ...(compact ? { minWidth: 552 } : {}), + padding: theme.spacing(3), + paddingTop: disablePaddingTop ? 0 : theme.spacing(2.8), + }, + list: { + scrollbarWidth: 'none', + '&::-webkit-scrollbar': { + display: 'none', + }, + }, + placeholder: { + textAlign: 'center', + height: 288, + paddingTop: theme.spacing(14), + boxSizing: 'border-box', + }, + search: { + backgroundColor: 'transparent !important', + border: `solid 1px ${MaskColorVar.twitterBorderLine}`, + }, +})) + +export interface PickTokenOptions { + disableNativeToken?: boolean + chainId?: ChainId + disableSearchBar?: boolean + keyword?: string + whitelist?: string[] + title?: string + blacklist?: string[] + tokens?: FungibleTokenDetailed[] + selectedTokens?: string[] +} + +export interface SelectTokenDialogProps extends PickTokenOptions { + open: boolean + onSelect?(token: FungibleTokenDetailed): void + onClose?(): void +} + +export const SelectTokenDialog: FC = ({ + open, + chainId, + disableSearchBar, + disableNativeToken, + tokens, + blacklist = EMPTY_LIST, + selectedTokens = EMPTY_LIST, + onSelect, + onClose, + title, +}) => { + const t = useSharedI18N() + const isDashboard = location.href.includes('dashboard.html') + const { networkIdentifier } = useBaseUIRuntime() + const compact = networkIdentifier === MINDS_ID + const { classes } = useStyles({ compact, disablePaddingTop: isDashboard }) + const { NATIVE_TOKEN_ADDRESS } = useTokenConstants(chainId) + // eslint-disable-next-line import/no-deprecated + const isMdScreen = useMediaQuery((theme) => theme.breakpoints.down('md')) + + const rowSize = useRowSize() + + return ( + + + + + + ) +} diff --git a/packages/shared/src/contexts/evm/TokenPicker/index.tsx b/packages/shared/src/contexts/evm/TokenPicker/index.tsx new file mode 100644 index 000000000000..7751c4be66ee --- /dev/null +++ b/packages/shared/src/contexts/evm/TokenPicker/index.tsx @@ -0,0 +1,66 @@ +import { defer, DeferTuple } from '@dimensiondev/kit' +import { EMPTY_LIST } from '@masknet/shared-base' +import type { FungibleTokenDetailed } from '@masknet/web3-shared-evm' +import { createContext, FC, useCallback, useContext, useMemo, useState } from 'react' +import { PickTokenOptions, SelectTokenDialog } from './SelectTokenDialog' + +interface ContextOptions { + pickToken: (options: PickTokenOptions) => Promise +} +const TokenPickerContext = createContext(null!) + +type PickerDeferTuple = DeferTuple + +interface Task { + id: number + promise: PickerDeferTuple[0] + resolve: PickerDeferTuple[1] + reject: PickerDeferTuple[2] + pickerOptions: PickTokenOptions +} + +let id = 0 +export const TokenPickerProvider: FC = ({ children }) => { + const [tasks, setTasks] = useState(EMPTY_LIST) + + const removeTask = useCallback((task: Task) => { + setTasks((list) => list.filter((t) => t !== task)) + }, []) + + const contextValue = useMemo(() => { + return { + pickToken: (options: PickTokenOptions) => { + const [promise, resolve, reject] = defer() + id += 1 + const newTask: Task = { id, promise, resolve, reject, pickerOptions: options } + setTasks((list) => [...list, newTask]) + return promise + }, + } + }, []) + + return ( + + {children} + {tasks.map((task) => ( + { + task.resolve(token) + removeTask(task) + }} + onClose={() => { + task.resolve(null) + removeTask(task) + }} + /> + ))} + + ) +} + +export const usePickToken = () => { + return useContext(TokenPickerContext).pickToken +} diff --git a/packages/shared/src/contexts/evm/TokenPicker/useRowSize.ts b/packages/shared/src/contexts/evm/TokenPicker/useRowSize.ts new file mode 100644 index 000000000000..59a8a05c5b5e --- /dev/null +++ b/packages/shared/src/contexts/evm/TokenPicker/useRowSize.ts @@ -0,0 +1,15 @@ +import { useEffect, useState } from 'react' + +export function useRowSize() { + const [rowSize, setRowSize] = useState(54) + + useEffect(() => { + try { + const fontSize = Number.parseFloat(getComputedStyle(document.documentElement).fontSize) + setRowSize(fontSize * 4) + } catch { + setRowSize(60) + } + }, []) + return rowSize +} diff --git a/packages/shared/src/contexts/evm/index.tsx b/packages/shared/src/contexts/evm/index.tsx new file mode 100644 index 000000000000..6f1f934b17e0 --- /dev/null +++ b/packages/shared/src/contexts/evm/index.tsx @@ -0,0 +1,8 @@ +import type { FC } from 'react' +import { TokenPickerProvider } from './TokenPicker' + +export * from './TokenPicker' + +export const EvmSharedUIProvider: FC = ({ children }) => { + return {children} +} diff --git a/packages/shared/src/contexts/index.ts b/packages/shared/src/contexts/index.ts new file mode 100644 index 000000000000..f56942ef31c8 --- /dev/null +++ b/packages/shared/src/contexts/index.ts @@ -0,0 +1,4 @@ +export * from './evm' +export * from './base' +export * from './components' +export * from './SharedContextProvider' diff --git a/packages/shared/src/index.ts b/packages/shared/src/index.ts index 832ef31a6879..91e163b62985 100644 --- a/packages/shared/src/index.ts +++ b/packages/shared/src/index.ts @@ -1,3 +1,4 @@ +export * from './contexts' export * from './hooks' export * from './wallet' export * from './UI' diff --git a/packages/shared/src/locales/en-US.json b/packages/shared/src/locales/en-US.json index 11514454ef72..134f72c9fc51 100644 --- a/packages/shared/src/locales/en-US.json +++ b/packages/shared/src/locales/en-US.json @@ -19,5 +19,6 @@ "address_viewer_address_name_dns": "DNS", "address_viewer_address_name_rns": "RNS", "address_viewer_address_name_address": "address", - "address_viewer_address_name_twitter": "twitter blue" + "address_viewer_address_name_twitter": "twitter blue", + "dialog_dismiss": "Dismiss" } diff --git a/packages/shared/tsconfig.json b/packages/shared/tsconfig.json index 49d1a5a6cdf3..b3e26abdc7e2 100644 --- a/packages/shared/tsconfig.json +++ b/packages/shared/tsconfig.json @@ -9,6 +9,7 @@ "references": [ { "path": "../web3-shared/evm" }, { "path": "../theme" }, + { "path": "../shared-base-ui" }, { "path": "../shared-base" }, { "path": "../shared-base-ui" }, { "path": "../icons" }, diff --git a/packages/theme/src/Components/Snackbar/index.tsx b/packages/theme/src/Components/Snackbar/index.tsx index 2b3a8b40a9d3..c2820d301b4d 100644 --- a/packages/theme/src/Components/Snackbar/index.tsx +++ b/packages/theme/src/Components/Snackbar/index.tsx @@ -104,7 +104,7 @@ to { return { root: { zIndex: 9999, - transform: typeof offsetY !== undefined ? `translateY(${80}px)` : 'none', + transform: typeof offsetY !== undefined ? `translateY(${offsetY}px)` : 'none', color: MaskColorVar.textLight, pointerEvents: 'inherit', }, diff --git a/packages/theme/src/customization/index.ts b/packages/theme/src/customization/index.ts new file mode 100644 index 000000000000..c9f6f047dc00 --- /dev/null +++ b/packages/theme/src/customization/index.ts @@ -0,0 +1 @@ +export * from './types' diff --git a/packages/theme/src/customization/types.ts b/packages/theme/src/customization/types.ts new file mode 100644 index 000000000000..82b7ebeaf57e --- /dev/null +++ b/packages/theme/src/customization/types.ts @@ -0,0 +1,6 @@ +type ClassNameMap = { [P in ClassKey]: string } + +export interface ComponentOverwriteConfig { + classes?: () => { classes: Partial> } + props?: (props: Props) => Props +} diff --git a/packages/theme/src/index.ts b/packages/theme/src/index.ts index a51f9b24b3e3..033c66de2224 100644 --- a/packages/theme/src/index.ts +++ b/packages/theme/src/index.ts @@ -40,6 +40,7 @@ export const MaskDarkTheme = MaskTheme('dark') export * from './makeStyles' export * from './Components' export * from './hooks' +export * from './customization' export * from './ShadowRoot' export * from './UIHelper/custom-ui-helper' export * from './CSSVariableInjector' diff --git a/packages/web3-shared/evm/hooks/useSocket.ts b/packages/web3-shared/evm/hooks/useSocket.ts index 232b6f8ce36b..60ed5774c8cc 100644 --- a/packages/web3-shared/evm/hooks/useSocket.ts +++ b/packages/web3-shared/evm/hooks/useSocket.ts @@ -18,7 +18,7 @@ export const useSocket = (message: SocketMessage) => { const [data, setData] = useState([]) const [state, setState] = useState(SocketState.init) const [error, setError] = useState() - const [id, setId] = useState(uuid()) + const [id, setId] = useState(uuid) const { value: socket, loading } = useAsyncRetry(() => providerSocket, []) const requestId = `${message.id}_${id}` diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 58c7fde01215..729a54eba920 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -12,7 +12,7 @@ importers: '@commitlint/cli': ^16.2.3 '@commitlint/config-conventional': ^16.2.1 '@dimensiondev/eslint-plugin': ^0.0.1-20220117062517-fd3cb01 - '@dimensiondev/kit': 0.0.0-20220223101101-4e6f3b9 + '@dimensiondev/kit': 0.0.0-20220228054820-f2378be '@dimensiondev/patch-package': ^6.5.0 '@emotion/cache': ^11.7.1 '@emotion/react': ^11.8.2 @@ -61,7 +61,7 @@ importers: web3-core: 1.5.2 web3-core-method: 1.5.2 dependencies: - '@dimensiondev/kit': 0.0.0-20220223101101-4e6f3b9 + '@dimensiondev/kit': 0.0.0-20220228054820-f2378be '@emotion/cache': 11.7.1 '@emotion/react': 11.8.2_e9d1a1f7836a0632db868fe80683b80d '@emotion/serialize': 1.0.2 @@ -136,6 +136,7 @@ importers: '@masknet/plugin-example': workspace:* '@masknet/plugin-flow': workspace:* '@masknet/plugin-infra': workspace:* + '@masknet/plugin-solana': workspace:* '@masknet/plugin-wallet': workspace:* '@masknet/public-api': workspace:* '@masknet/shared': workspace:* @@ -190,6 +191,7 @@ importers: '@masknet/plugin-example': link:../plugins/example '@masknet/plugin-flow': link:../plugins/Flow '@masknet/plugin-infra': link:../plugin-infra + '@masknet/plugin-solana': link:../plugins/Solana '@masknet/plugin-wallet': link:../plugins/Wallet '@masknet/public-api': link:../public-api '@masknet/shared': link:../shared @@ -999,6 +1001,7 @@ importers: '@masknet/icons': workspace:* '@masknet/plugin-infra': workspace:* '@masknet/shared-base': workspace:* + '@masknet/shared-base-ui': workspace:* '@masknet/theme': workspace:* '@masknet/web3-shared-base': workspace:* '@masknet/web3-shared-evm': workspace:* @@ -1011,13 +1014,13 @@ importers: react-feather: ^2.0.9 react-use: ^17.3.2 urlcat: ^2.0.4 - use-subscription: ^1.5.1 - uuid: ^8.3.2 + use-subscription: ^1.6.0 dependencies: '@dimensiondev/holoflows-kit': 0.9.0-20210902104757-7c3d0d0 '@masknet/icons': link:../icons '@masknet/plugin-infra': link:../plugin-infra '@masknet/shared-base': link:../shared-base + '@masknet/shared-base-ui': link:../shared-base-ui '@masknet/theme': link:../theme '@masknet/web3-shared-base': link:../web3-shared/base '@masknet/web3-shared-evm': link:../web3-shared/evm @@ -1030,8 +1033,7 @@ importers: react-feather: 2.0.9_react@18.0.0-rc.3 react-use: 17.3.2_581fa33d3647c30d8078674dcd1b240a urlcat: 2.0.4 - use-subscription: 1.5.1_react@18.0.0-rc.3 - uuid: 8.3.2 + use-subscription: 1.6.0_react@18.0.0-rc.3 packages/shared-base: specifiers: @@ -1085,14 +1087,18 @@ importers: specifiers: '@dimensiondev/holoflows-kit': ^0.9.0-20210902104757-7c3d0d0 '@masknet/shared-base': workspace:* + '@types/use-subscription': ^1.0.0 + '@types/uuid': ^8.3.4 react-use: ^17.3.2 - use-subscription: ^1.5.1 + use-subscription: ^1.6.0 uuid: ^8.3.2 dependencies: '@dimensiondev/holoflows-kit': 0.9.0-20210902104757-7c3d0d0 '@masknet/shared-base': link:../shared-base + '@types/use-subscription': 1.0.0 + '@types/uuid': 8.3.4 react-use: 17.3.2_581fa33d3647c30d8078674dcd1b240a - use-subscription: 1.5.1_react@18.0.0-rc.3 + use-subscription: 1.6.0_react@18.0.0-rc.3 uuid: 8.3.2 packages/storybook-shared: @@ -4391,13 +4397,6 @@ packages: source-map-support: 0.5.21 dev: true - /@babel/runtime/7.15.4: - resolution: {integrity: sha512-99catp6bHCaxr4sJ/DbTGgHS4+Rs2RVd2g7iOap6SLGPDknRK9ztKNsE/Fg6QhSeh1FGE5f6gHGQmvvn3I3xhw==} - engines: {node: '>=6.9.0'} - dependencies: - regenerator-runtime: 0.13.9 - dev: false - /@babel/runtime/7.16.3: resolution: {integrity: sha512-WBwekcqacdY2e9AF/Q7WLFUWmdJGJTkbjqTjoMDgXkVZ3ZRUvOPsLb5KdwISoQVsbP+DQzVZW4Zhci0DvpbNTQ==} engines: {node: '>=6.9.0'} @@ -5193,8 +5192,8 @@ packages: webextension-polyfill: 0.8.0 dev: false - /@dimensiondev/kit/0.0.0-20220223101101-4e6f3b9: - resolution: {integrity: sha512-xk9rACwU2Iu+81BfnL1ykGofG+HuR/aMmYo4GZ1zyv32vZwe73B21z1GNGLq6XbYVjqNGa3puWoHZwDizAP4SA==, tarball: download/@dimensiondev/kit/0.0.0-20220223101101-4e6f3b9/a1b996a27d8d62c75d54a4a9d6b6544b45fe464288c83df31fccbbd2685b3a54} + /@dimensiondev/kit/0.0.0-20220228054820-f2378be: + resolution: {integrity: sha512-B+5bj3+nTqwp4nigrwXxKK3iQeCn1tlFOuYeqzPCJY/wqMrM+GsAyYdw5BPjFwn5+9uiZ5xSZcnLhSF/6EgjhQ==, tarball: download/@dimensiondev/kit/0.0.0-20220228054820-f2378be/8352c3f70e1a38376b321dd05989ad48c80a260785561da3910520e28560b26b} dependencies: lodash-es: 4.17.21 dev: false @@ -22984,10 +22983,10 @@ packages: react: '>=16.6.0' react-dom: '>=16.6.0' dependencies: - '@babel/runtime': 7.15.4 + '@babel/runtime': 7.17.2 dom-helpers: 5.2.1 loose-envify: 1.4.0 - prop-types: 15.7.2 + prop-types: 15.8.1 react: 18.0.0-rc.3 react-dom: 18.0.0-rc.3_react@18.0.0-rc.3 dev: false @@ -26201,6 +26200,14 @@ packages: react: 18.0.0-rc.3 dev: false + /use-subscription/1.6.0_react@18.0.0-rc.3: + resolution: {integrity: sha512-0Y/cTLlZfw547tJhJMoRA16OUbVqRm6DmvGpiGbmLST6BIA5KU5cKlvlz8DVMrACnWpyEjCkgmhLatthP4jUbA==} + peerDependencies: + react: ^18.0.0 + dependencies: + react: 18.0.0-rc.3 + dev: false + /use/3.1.1: resolution: {integrity: sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==} engines: {node: '>=0.10.0'} From 77e52259100be3a7aed6f59047f3a1f7eb9b3da7 Mon Sep 17 00:00:00 2001 From: UncleBill Date: Sat, 2 Apr 2022 16:39:02 +0800 Subject: [PATCH 28/42] fix(tip): hide tip button when evm is not actived (#5982) --- .../InjectedComponents/ProfileTabContent.tsx | 29 ++++++++++++------- packages/mask/src/plugins/EVM/constants.ts | 6 ++-- .../src/plugins/NextID/SNSAdaptor/index.tsx | 6 ++-- .../plugins/NextID/components/NextIdPage.tsx | 5 ++-- .../injection/PostActions/index.tsx | 4 +-- packages/plugin-infra/src/hooks/index.ts | 1 + .../src/hooks/useAvailablePlugins.ts | 21 ++++++++++++++ .../src/utils/createInjectHooksRenderer.tsx | 24 +++++++-------- 8 files changed, 63 insertions(+), 33 deletions(-) create mode 100644 packages/plugin-infra/src/hooks/useAvailablePlugins.ts diff --git a/packages/mask/src/components/InjectedComponents/ProfileTabContent.tsx b/packages/mask/src/components/InjectedComponents/ProfileTabContent.tsx index 53966a9a2460..fa30e0d04506 100644 --- a/packages/mask/src/components/InjectedComponents/ProfileTabContent.tsx +++ b/packages/mask/src/components/InjectedComponents/ProfileTabContent.tsx @@ -1,17 +1,24 @@ -import { useEffect, useMemo, useState } from 'react' -import { useUpdateEffect } from 'react-use' -import { first } from 'lodash-unified' -import { NextIDPlatform, EMPTY_LIST } from '@masknet/shared-base' -import { Box, CircularProgress } from '@mui/material' +import { + createInjectHooksRenderer, + Plugin, + PluginId, + useActivatedPluginsSNSAdaptor, + useAvailablePlugins, +} from '@masknet/plugin-infra' +import { EMPTY_LIST, NextIDPlatform } from '@masknet/shared-base' import { makeStyles, useStylesExtends } from '@masknet/theme' import { useAddressNames } from '@masknet/web3-shared-evm' -import { createInjectHooksRenderer, useActivatedPluginsSNSAdaptor, Plugin, PluginId } from '@masknet/plugin-infra' -import { PageTab } from '../InjectedComponents/PageTab' -import { MaskMessages, useI18N, useLocationChange } from '../../utils' +import { Box, CircularProgress } from '@mui/material' +import { first } from 'lodash-unified' +import { useEffect, useMemo, useState } from 'react' +import { useUpdateEffect } from 'react-use' +import { activatedSocialNetworkUI } from '../../social-network' +import { MaskMessages } from '../../utils' +import { useLocationChange } from '../../utils/hooks/useLocationChange' import { useCurrentVisitingIdentity, useLastRecognizedIdentity } from '../DataSource/useActivatedUI' import { useNextIDBoundByPlatform } from '../DataSource/useNextID' import { usePersonaConnectStatus } from '../DataSource/usePersonaConnectStatus' -import { activatedSocialNetworkUI } from '../../social-network' +import { PageTab } from '../InjectedComponents/PageTab' function getTabContent(tabId: string) { return createInjectHooksRenderer(useActivatedPluginsSNSAdaptor.visibility.useAnyMode, (x) => { @@ -36,7 +43,6 @@ const useStyles = makeStyles()((theme) => ({ export interface ProfileTabContentProps extends withClasses<'text' | 'button' | 'root'> {} export function ProfileTabContent(props: ProfileTabContentProps) { - const { t } = useI18N() const classes = useStylesExtends(useStyles(), props) const [hidden, setHidden] = useState(true) @@ -55,7 +61,8 @@ export function ProfileTabContent(props: ProfileTabContentProps) { currentIdentity.identifier.userId === identity.identifier.userId && personaList.findIndex((persona) => persona?.persona === currentConnectedPersona?.publicHexKey) === -1 - const tabs = useActivatedPluginsSNSAdaptor('any') + const activatedPlugins = useActivatedPluginsSNSAdaptor('any') + const tabs = useAvailablePlugins(activatedPlugins) .flatMap((x) => x.ProfileTabs?.map((y) => ({ ...y, pluginID: x.ID })) ?? []) .filter((z) => z.Utils?.shouldDisplay?.(identity, addressNames) ?? true) .sort((a, z) => { diff --git a/packages/mask/src/plugins/EVM/constants.ts b/packages/mask/src/plugins/EVM/constants.ts index 2c17f3d96cbf..2a508a0600db 100644 --- a/packages/mask/src/plugins/EVM/constants.ts +++ b/packages/mask/src/plugins/EVM/constants.ts @@ -1,8 +1,8 @@ -import { PluginId, Web3Plugin } from '@masknet/plugin-infra' +import { NetworkPluginID, Web3Plugin } from '@masknet/plugin-infra' import { ChainId, NetworkType, ProviderType } from '@masknet/web3-shared-evm' -export const PLUGIN_ID = PluginId.EVM -export const PLUGIN_META_KEY = `${PluginId.EVM}:1` +export const PLUGIN_ID = NetworkPluginID.PLUGIN_EVM +export const PLUGIN_META_KEY = `${PLUGIN_ID}:1` export const PLUGIN_NAME = 'EVM' export const PLUGIN_ICON = '\u039E' export const PLUGIN_DESCRIPTION = '' diff --git a/packages/mask/src/plugins/NextID/SNSAdaptor/index.tsx b/packages/mask/src/plugins/NextID/SNSAdaptor/index.tsx index 139ece72debe..c888a6006157 100644 --- a/packages/mask/src/plugins/NextID/SNSAdaptor/index.tsx +++ b/packages/mask/src/plugins/NextID/SNSAdaptor/index.tsx @@ -1,11 +1,11 @@ import type { Plugin } from '@masknet/plugin-infra' import { EMPTY_LIST } from '@masknet/shared-base' +import { Flags } from '../../../../shared' import { base } from '../base' -import { PLUGIN_ID } from '../constants' import { NextIdPage } from '../components/NextIdPage' -import { RootContext } from '../contexts' import { PostTipButton, TipTaskManager } from '../components/Tip' -import { Flags } from '../../../../shared' +import { PLUGIN_ID } from '../constants' +import { RootContext } from '../contexts' const sns: Plugin.SNSAdaptor.Definition = { ...base, diff --git a/packages/mask/src/plugins/NextID/components/NextIdPage.tsx b/packages/mask/src/plugins/NextID/components/NextIdPage.tsx index 96d7281e1ce5..24232623a75b 100644 --- a/packages/mask/src/plugins/NextID/components/NextIdPage.tsx +++ b/packages/mask/src/plugins/NextID/components/NextIdPage.tsx @@ -58,12 +58,13 @@ export function NextIdPage({ personaList }: NextIDPageProps) { const currentProfileIdentifier = useLastRecognizedIdentity() const visitingPersonaIdentifier = useCurrentVisitingIdentity() const personaConnectStatus = usePersonaConnectStatus() - const { reset, isVerified, action } = useNextIDConnectStatus() + const { reset, isVerified } = useNextIDConnectStatus() const [openBindDialog, toggleBindDialog] = useState(false) const [unbindAddress, setUnBindAddress] = useState() const platform = activatedSocialNetworkUI.configuration.nextIDConfig?.platform as NextIDPlatform const isOwn = currentProfileIdentifier.identifier.toText() === visitingPersonaIdentifier.identifier.toText() + const tipable = !isOwn const personaActionButton = useMemo(() => { if (!personaConnectStatus.action) return null @@ -153,7 +154,7 @@ export function NextIdPage({ personaList }: NextIDPageProps) { {bindings.proofs.map((x) => ( (plugins: T[]) { + const networkPluginId = useCurrentWeb3NetworkPluginID() + const chainId = useChainId(networkPluginId) + return useMemo( + () => plugins.filter((plugin) => checkPluginAvailable(plugin, networkPluginId, chainId)), + [plugins, networkPluginId, chainId], + ) +} diff --git a/packages/plugin-infra/src/utils/createInjectHooksRenderer.tsx b/packages/plugin-infra/src/utils/createInjectHooksRenderer.tsx index 2da5547361b3..1e68250fbe85 100644 --- a/packages/plugin-infra/src/utils/createInjectHooksRenderer.tsx +++ b/packages/plugin-infra/src/utils/createInjectHooksRenderer.tsx @@ -1,9 +1,9 @@ -import { useEffect, useState, useRef, memo, createContext, useContext } from 'react' import { ErrorBoundary } from '@masknet/shared-base-ui' import { ShadowRootIsolation } from '@masknet/theme' -import type { Plugin } from '../types' -import { usePluginI18NField, PluginWrapperComponent, PluginWrapperMethods } from '../hooks' +import { createContext, memo, useContext, useEffect, useRef, useState } from 'react' +import { PluginWrapperComponent, PluginWrapperMethods, useAvailablePlugins, usePluginI18NField } from '../hooks' import { PluginWrapperMethodsContext } from '../hooks/usePluginWrapper' +import type { Plugin } from '../types' type Inject = Plugin.InjectUI type Raw = Plugin.InjectUIRaw @@ -43,15 +43,15 @@ export function createInjectHooksRenderer ( - - - - - - )) + const allPlugins = usePlugins() + const availablePlugins = useAvailablePlugins(allPlugins) as PluginDefinition[] + const all = availablePlugins.filter(pickInjectorHook).map((plugin) => ( + + + + + + )) return <>{all} } return memo(function PluginsInjectionHookRenderErrorBoundary(props: PropsType) { From e62d2cf2da4abbaa17276e173d646e1fa241854a Mon Sep 17 00:00:00 2001 From: UncleBill Date: Wed, 6 Apr 2022 12:22:53 +0800 Subject: [PATCH 29/42] feat: tip NFT (#6013) * fix(tip): set current chain as default tip chain * feat: tip NFT * fix: add token * token section * fix: follow up bug reports * fix: trigger update after ws responses * fix: cleanup useEffect * fix: add loading status * fix: set dialog title higher * Apply suggestions from code review Co-authored-by: guanbinrui <52657989+guanbinrui@users.noreply.github.com> * fix: reset txstate before sending * fix: ui issues * fixup! fix: ui issues * fix: follow up reports * fix: reset AddDialog after closing improve selected checking * fix: sync token adding to dashboard * fix: typo and address checking * fixup! fix: typo and address checking * fix: add loading Co-authored-by: guanbinrui <52657989+guanbinrui@users.noreply.github.com> --- .../components/CollectibleList/index.tsx | 21 +- packages/icons/general/Drop2.tsx | 12 ++ packages/icons/general/Edit2.tsx | 13 ++ packages/icons/general/index.ts | 2 + .../UI/Web3State/createNonFungibleToken.ts | 27 +++ .../plugins/EVM/UI/Web3State/getAssetsFn.ts | 57 ++--- .../src/plugins/NextID/SNSAdaptor/index.tsx | 5 +- .../NextID/components/Tip/AddDialog.tsx | 156 ++++++++++++++ .../components/Tip/NFTSection/NFTList.tsx | 183 ++++++++++------ .../components/Tip/NFTSection/index.tsx | 196 ++++++++++-------- .../NextID/components/Tip/TipDialog.tsx | 172 +++++++++++++-- .../plugins/NextID/components/Tip/TipForm.tsx | 131 +++++++----- .../components/Tip/TokenSection/index.tsx | 57 +++++ .../NextID/contexts/TargetChainIdContext.ts | 6 +- .../plugins/NextID/contexts/Tip/TipContext.ts | 11 +- .../NextID/contexts/Tip/TipTaskProvider.tsx | 33 ++- .../plugins/NextID/contexts/Tip/useNftTip.ts | 37 ++-- .../NextID/contexts/Tip/useTipValidate.ts | 6 +- .../src/plugins/NextID/locales/en-US.json | 14 +- .../mask/src/plugins/NextID/storage/index.ts | 38 ++++ packages/mask/src/plugins/NextID/types/tip.ts | 2 + packages/plugin-infra/src/web3-types.ts | 13 ++ .../src/UI/components/AssetPlayer/index.tsx | 5 +- .../src/UI/components/ImageIcon/index.tsx | 2 +- .../NFTCardStyledAssetPlayer/index.tsx | 14 +- .../contexts/components/InjectedDialog.tsx | 15 +- .../evm/hooks/useERC721ContractDetailed.ts | 47 ++--- .../evm/hooks/useERC721TokenDetailed.ts | 54 +++-- .../hooks/useERC721TokenTransferCallback.ts | 6 +- packages/web3-shared/evm/utils/formatter.ts | 2 +- 30 files changed, 974 insertions(+), 363 deletions(-) create mode 100644 packages/icons/general/Drop2.tsx create mode 100644 packages/icons/general/Edit2.tsx create mode 100644 packages/mask/src/plugins/EVM/UI/Web3State/createNonFungibleToken.ts create mode 100644 packages/mask/src/plugins/NextID/components/Tip/AddDialog.tsx create mode 100644 packages/mask/src/plugins/NextID/components/Tip/TokenSection/index.tsx create mode 100644 packages/mask/src/plugins/NextID/storage/index.ts diff --git a/packages/dashboard/src/pages/Wallets/components/CollectibleList/index.tsx b/packages/dashboard/src/pages/Wallets/components/CollectibleList/index.tsx index d6834fbed62e..695e940d787f 100644 --- a/packages/dashboard/src/pages/Wallets/components/CollectibleList/index.tsx +++ b/packages/dashboard/src/pages/Wallets/components/CollectibleList/index.tsx @@ -64,6 +64,18 @@ export const CollectibleList = memo(({ selectedNetwork }) Asset?.getNonFungibleAssets?.(account, { page: page, size: 20 }, undefined, selectedNetwork || undefined), [account, Asset?.getNonFungibleAssets, network, selectedNetwork], ) + useEffect(() => { + const unsubscribeTokens = PluginMessages.Wallet.events.erc721TokensUpdated.on(() => retry()) + const unsubscribeSocket = PluginMessages.Wallet.events.socketMessageUpdated.on((info) => { + if (!info.done) { + retry() + } + }) + return () => { + unsubscribeTokens() + unsubscribeSocket() + } + }, [retry]) useEffect(() => { if (!loadingSize) return @@ -86,15 +98,6 @@ export const CollectibleList = memo(({ selectedNetwork }) [currentPluginId], ) - useEffect(() => { - PluginMessages.Wallet.events.erc721TokensUpdated.on(() => retry()) - PluginMessages.Wallet.events.socketMessageUpdated.on((info) => { - if (!info.done) { - retry() - } - }) - }, [retry]) - const hasNextPage = (page + 1) * loadingSize < value.data.length const isLoading = renderData.length === 0 && isQuerying diff --git a/packages/icons/general/Drop2.tsx b/packages/icons/general/Drop2.tsx new file mode 100644 index 000000000000..c1c081af5b04 --- /dev/null +++ b/packages/icons/general/Drop2.tsx @@ -0,0 +1,12 @@ +import { createIcon } from '../utils' + +export const Drop2Icon = createIcon( + 'Drop2Icon', + + + , + '0 0 20 24', +) diff --git a/packages/icons/general/Edit2.tsx b/packages/icons/general/Edit2.tsx new file mode 100644 index 000000000000..0e05c13325dd --- /dev/null +++ b/packages/icons/general/Edit2.tsx @@ -0,0 +1,13 @@ +import { createIcon } from '../utils' +import type { SvgIcon } from '@mui/material' + +export const Edit2Icon: typeof SvgIcon = createIcon( + 'Edit2Icon', + + + , + '0 0 24 24', +) diff --git a/packages/icons/general/index.ts b/packages/icons/general/index.ts index a3d4ce6901cf..f9e5c503e831 100644 --- a/packages/icons/general/index.ts +++ b/packages/icons/general/index.ts @@ -12,6 +12,7 @@ export * from './Link' export * from './Author' export * from './Settings' export * from './Edit' +export * from './Edit2' export * from './ArrowDownRound' export * from './ArrowUpRound' export * from './Empty' @@ -79,6 +80,7 @@ export * from './ChevronUp' export * from './BestTrade' export * from './Retweet' export * from './Drop' +export * from './Drop2' export * from './Right' export * from './Tutorial' export * from './AssetLoading' diff --git a/packages/mask/src/plugins/EVM/UI/Web3State/createNonFungibleToken.ts b/packages/mask/src/plugins/EVM/UI/Web3State/createNonFungibleToken.ts new file mode 100644 index 000000000000..218ba80a7734 --- /dev/null +++ b/packages/mask/src/plugins/EVM/UI/Web3State/createNonFungibleToken.ts @@ -0,0 +1,27 @@ +import { TokenType, Web3Plugin } from '@masknet/plugin-infra' +import type { ERC721TokenDetailed } from '@masknet/web3-shared-evm' + +export function createNonFungibleToken(token: ERC721TokenDetailed) { + return { + ...token, + id: `${token.contractDetailed.address}_${token.tokenId}`, + tokenId: token.tokenId, + chainId: token.contractDetailed.chainId, + type: TokenType.NonFungible, + name: token.info.name ?? `${token.contractDetailed.name} ${token.tokenId}`, + description: token.info.description ?? '', + owner: token.info.owner, + contract: { + ...token.contractDetailed, + type: TokenType.NonFungible, + id: token.contractDetailed.address, + }, + metadata: { + name: token.info.name ?? `${token.contractDetailed.name} ${token.tokenId}`, + description: token.info.description ?? '', + mediaType: 'Unknown', + iconURL: token.contractDetailed.iconURL, + assetURL: token.info.mediaUrl, + }, + } as Web3Plugin.NonFungibleToken +} diff --git a/packages/mask/src/plugins/EVM/UI/Web3State/getAssetsFn.ts b/packages/mask/src/plugins/EVM/UI/Web3State/getAssetsFn.ts index 69f40729cae1..f767bbfb913f 100644 --- a/packages/mask/src/plugins/EVM/UI/Web3State/getAssetsFn.ts +++ b/packages/mask/src/plugins/EVM/UI/Web3State/getAssetsFn.ts @@ -1,33 +1,34 @@ -import Web3 from 'web3' +import { Pageable, Pagination, TokenType, Web3Plugin } from '@masknet/plugin-infra' +import BalanceCheckerABI from '@masknet/web3-contracts/abis/BalanceChecker.json' +import ERC721ABI from '@masknet/web3-contracts/abis/ERC721.json' +import type { ERC721 } from '@masknet/web3-contracts/types/ERC721' +import { TokenPrice } from '@masknet/web3-providers' +import { pow10 } from '@masknet/web3-shared-base' import { + ChainId, createContract, + createExternalProvider, createNativeToken, + CurrencyType, ERC721TokenDetailed, formatEthereumAddress, - getERC721TokenDetailedFromChain, + FungibleAssetProvider, + getCoinGeckoCoinId, getERC721TokenAssetFromChain, + getERC721TokenDetailedFromChain, getEthereumConstants, isSameAddress, - Web3ProviderType, - FungibleAssetProvider, - createExternalProvider, - getCoinGeckoCoinId, - CurrencyType, PriceRecord, - ChainId, + Web3ProviderType, } from '@masknet/web3-shared-evm' import BigNumber from 'bignumber.js' -import { Pageable, Pagination, TokenType, Web3Plugin } from '@masknet/plugin-infra' -import BalanceCheckerABI from '@masknet/web3-contracts/abis/BalanceChecker.json' -import ERC721ABI from '@masknet/web3-contracts/abis/ERC721.json' -import type { AbiItem } from 'web3-utils' import { uniqBy } from 'lodash-unified' +import Web3 from 'web3' +import type { AbiItem } from 'web3-utils' import { PLUGIN_NETWORKS } from '../../constants' import { makeSortAssertWithoutChainFn } from '../../utils/token' import { createGetLatestBalance } from './createGetLatestBalance' -import type { ERC721 } from '@masknet/web3-contracts/types/ERC721' -import { pow10 } from '@masknet/web3-shared-base' -import { TokenPrice } from '@masknet/web3-providers' +import { createNonFungibleToken } from './createNonFungibleToken' // tokens unavailable neither from api or balance checker. // https://forum.conflux.fun/t/how-to-upvote-debank-proposal-for-conflux-espace-integration/13935 @@ -215,31 +216,7 @@ export const getNonFungibleTokenFn = const tokenFromProvider = socket.getResult(socketId) const allData: Web3Plugin.NonFungibleToken[] = [...tokenInDb, ...tokenFromProvider] - .map( - (x) => - ({ - ...x, - id: `${x.contractDetailed.address}_${x.tokenId}`, - tokenId: x.tokenId, - chainId: x.contractDetailed.chainId, - type: TokenType.NonFungible, - name: x.info.name ?? `${x.contractDetailed.name} ${x.tokenId}`, - description: x.info.description ?? '', - owner: x.info.owner, - contract: { - ...x.contractDetailed, - type: TokenType.NonFungible, - id: x.contractDetailed.address, - }, - metadata: { - name: x.info.name ?? `${x.contractDetailed.name} ${x.tokenId}`, - description: x.info.description ?? '', - mediaType: 'Unknown', - iconURL: x.contractDetailed.iconURL, - assetURL: x.info.mediaUrl, - }, - } as Web3Plugin.NonFungibleToken), - ) + .map(createNonFungibleToken) .filter((x) => isSameAddress(x.owner, address)) .filter((x) => !network || x.chainId === network.chainId) diff --git a/packages/mask/src/plugins/NextID/SNSAdaptor/index.tsx b/packages/mask/src/plugins/NextID/SNSAdaptor/index.tsx index c888a6006157..f95c8b0dc1fb 100644 --- a/packages/mask/src/plugins/NextID/SNSAdaptor/index.tsx +++ b/packages/mask/src/plugins/NextID/SNSAdaptor/index.tsx @@ -6,10 +6,13 @@ import { NextIdPage } from '../components/NextIdPage' import { PostTipButton, TipTaskManager } from '../components/Tip' import { PLUGIN_ID } from '../constants' import { RootContext } from '../contexts' +import { setupStorage, storageDefaultValue } from '../storage' const sns: Plugin.SNSAdaptor.Definition = { ...base, - init() {}, + init(signal, context) { + setupStorage(context.createKVStorage('memory', storageDefaultValue)) + }, ProfileTabs: [ { ID: `${PLUGIN_ID}_tabContent`, diff --git a/packages/mask/src/plugins/NextID/components/Tip/AddDialog.tsx b/packages/mask/src/plugins/NextID/components/Tip/AddDialog.tsx new file mode 100644 index 000000000000..be9080da903f --- /dev/null +++ b/packages/mask/src/plugins/NextID/components/Tip/AddDialog.tsx @@ -0,0 +1,156 @@ +import { useNetworkDescriptors } from '@masknet/plugin-infra' +import { ImageIcon, InjectedDialog, InjectedDialogProps } from '@masknet/shared' +import { makeStyles } from '@masknet/theme' +import { + ERC721TokenDetailed, + getERC721ContractDetailed, + getERC721TokenDetailed, + isSameAddress, + useAccount, + useChainId, + useERC721TokenContract, +} from '@masknet/web3-shared-evm' +import { Button, DialogContent, FormControl, TextField, Typography } from '@mui/material' +import { FC, useCallback, useEffect, useMemo, useState } from 'react' +import { useAsyncFn } from 'react-use' +import { EthereumAddress } from 'wallet.ts' +import { WalletRPC } from '../../../Wallet/messages' +import { useI18N } from '../../locales' + +const useStyles = makeStyles()((theme) => ({ + addButton: { + marginLeft: 'auto', + }, + chain: { + display: 'flex', + }, + row: { + marginTop: theme.spacing(1.5), + }, + chainName: { + marginLeft: theme.spacing(1), + }, + error: { + display: 'flex', + height: 16, + alignItems: 'center', + color: theme.palette.error.main, + '&::before': { + backgroundColor: theme.palette.error.main, + content: '""', + width: 2, + height: 16, + marginRight: theme.spacing(0.5), + }, + }, +})) + +interface Props extends InjectedDialogProps { + onAdd?(token: ERC721TokenDetailed): void +} + +export const AddDialog: FC = ({ onAdd, onClose, ...rest }) => { + const { classes } = useStyles() + const chainId = useChainId() + const account = useAccount() + const [contractAddress, setContractAddress] = useState('') + const [tokenId, setTokenId] = useState('') + const t = useI18N() + const allNetworks = useNetworkDescriptors() + const network = useMemo(() => allNetworks.find((n) => n.chainId === chainId), [allNetworks, chainId]) + const erc721TokenContract = useERC721TokenContract(contractAddress) + + const [, checkOwner] = useAsyncFn(async () => { + if (!erc721TokenContract || !account) return false + const ownerAddress = await erc721TokenContract.methods.ownerOf(tokenId).call() + return isSameAddress(ownerAddress, account) + }, [erc721TokenContract, tokenId, account]) + + const [message, setMessage] = useState('') + const reset = useCallback(() => { + setMessage('') + setContractAddress('') + setTokenId('') + }, []) + + useEffect(() => { + setMessage('') + }, [tokenId, contractAddress]) + + const [state, handleAdd] = useAsyncFn(async () => { + if (!erc721TokenContract || !EthereumAddress.isValid(contractAddress)) { + setMessage(t.tip_add_collectibles_error()) + return + } + + const hasOwnership = await checkOwner() + if (!hasOwnership) { + setMessage(t.tip_add_collectibles_error()) + return + } + const erc721ContractDetailed = await getERC721ContractDetailed(erc721TokenContract, contractAddress, chainId) + const erc721TokenDetailed = await getERC721TokenDetailed( + erc721ContractDetailed, + erc721TokenContract, + tokenId, + chainId, + ) + + if (!erc721TokenDetailed) { + setMessage(t.tip_add_collectibles_error()) + return + } + await WalletRPC.addToken(erc721TokenDetailed) + onAdd?.(erc721TokenDetailed) + reset() + }, [onAdd, t, contractAddress, tokenId]) + + const handleClose = useCallback(() => { + onClose?.() + reset() + }, [onClose]) + + const addButton = useMemo(() => { + return ( + + ) + }, [t, handleAdd, state.loading]) + + if (!network) return null + return ( + + +
+ + {network.name} +
+ + setContractAddress(e.currentTarget.value)} + placeholder={t.tip_add_collectibles_contract_address()} + /> + + + setTokenId(e.currentTarget.value)} + placeholder={t.tip_add_collectibles_token_id()} + /> + + {message ? ( + + {message} + + ) : null} +
+
+ ) +} diff --git a/packages/mask/src/plugins/NextID/components/Tip/NFTSection/NFTList.tsx b/packages/mask/src/plugins/NextID/components/Tip/NFTSection/NFTList.tsx index f19c33b3bcbf..bafa0ba86ed1 100644 --- a/packages/mask/src/plugins/NextID/components/Tip/NFTSection/NFTList.tsx +++ b/packages/mask/src/plugins/NextID/components/Tip/NFTSection/NFTList.tsx @@ -1,16 +1,17 @@ +import { useWeb3State, Web3Plugin } from '@masknet/plugin-infra' import { NFTCardStyledAssetPlayer } from '@masknet/shared' -import { makeStyles } from '@masknet/theme' -import { ERC721TokenDetailed, formatNFT_TokenId, useChainId } from '@masknet/web3-shared-evm' -import { Checkbox, List, ListItem, Radio, Typography } from '@mui/material' +import { makeStyles, ShadowRootTooltip } from '@masknet/theme' +import { formatNFT_TokenId, isSameAddress, useChainId } from '@masknet/web3-shared-evm' +import { Checkbox, Link, List, ListItem, Radio } from '@mui/material' import classnames from 'classnames' import { noop } from 'lodash-unified' import { FC, useCallback } from 'react' +import type { TipNFTKeyPair } from '../../../types' interface Props { - selectedIds: string[] - tokens: ERC721TokenDetailed[] - enableTokenIds?: string[] - onChange?: (ids: string[]) => void + selectedPairs: TipNFTKeyPair[] + tokens: Web3Plugin.NonFungibleToken[] + onChange?: (id: string | null, contractAddress: string) => void limit?: number className: string } @@ -21,111 +22,157 @@ const useStyles = makeStyles()((theme) => ({ right: 0, top: 0, }, + list: { + gridGap: 13, + display: 'grid', + gridTemplateColumns: 'repeat(5, 1fr)', + }, nftItem: { position: 'relative', cursor: 'pointer', - background: theme.palette.mode === 'light' ? '#fff' : '#2F3336', + background: theme.palette.mode === 'light' ? '#EDEFEF' : '#2F3336', display: 'flex', overflow: 'hidden', padding: 0, flexDirection: 'column', - borderRadius: 8, - height: 180, + borderRadius: 12, + height: 100, userSelect: 'none', - width: 120, + width: 100, justifyContent: 'center', }, disabled: { opacity: 0.5, cursor: 'not-allowed', }, + selected: { + position: 'relative', + '&::after': { + position: 'absolute', + border: `2px solid ${theme.palette.primary.main}`, + content: '""', + left: 0, + top: 0, + pointerEvents: 'none', + boxSizing: 'border-box', + width: '100%', + height: '100%', + borderRadius: 12, + }, + }, + unselected: { + opacity: 0.5, + }, loadingFailImage: { width: 64, height: 64, }, + assetPlayerIframe: { + height: 100, + width: 100, + }, + imgWrapper: { + height: '100px !important', + width: '100px !important', + img: { + height: '100%', + width: '100%', + }, + }, + tooltip: { + marginBottom: `${theme.spacing(0.5)} !important`, + }, })) -function arrayRemove(arr: T[], item: T): T[] { - const idx = arr.indexOf(item) - return arr.splice(idx, 1) -} - interface NFTItemProps { - token: ERC721TokenDetailed + token: Web3Plugin.NonFungibleToken } export const NFTItem: FC = ({ token }) => { const { classes } = useStyles() const chainId = useChainId() return ( - <> - - - {formatNFT_TokenId(token.tokenId, 2)} - - + ) } -export const NFTList: FC = ({ selectedIds, tokens, enableTokenIds = [], onChange, limit = 1, className }) => { +const includes = (pairs: TipNFTKeyPair[], pair: TipNFTKeyPair): boolean => { + return !!pairs.find(([address, tokenId]) => isSameAddress(address, pair[0]) && tokenId === pair[1]) +} + +export const NFTList: FC = ({ selectedPairs, tokens, onChange, limit = 1, className }) => { const { classes } = useStyles() const isRadio = limit === 1 - const reachedLimit = selectedIds.length >= limit + const reachedLimit = selectedPairs.length >= limit const toggleItem = useCallback( - (currentId: string) => { - if (!onChange) return - if (isRadio) return onChange([currentId]) - let newIds = [...selectedIds] - if (selectedIds.includes(currentId)) { - arrayRemove(newIds, currentId) - } else if (!reachedLimit) { - newIds = [...selectedIds, currentId] - } - onChange(newIds) + (currentId: string | null, contractAddress: string) => { + onChange?.(currentId, contractAddress) }, - [selectedIds, onChange, isRadio, reachedLimit], + [onChange, isRadio, reachedLimit], ) const SelectComponent = isRadio ? Radio : Checkbox + const { Utils } = useWeb3State() return ( - + {tokens.map((token) => { - const isNotOwned = !enableTokenIds.includes(token.tokenId) - const disabled = (!isRadio && reachedLimit && !selectedIds.includes(token.tokenId)) || isNotOwned + const selected = includes(selectedPairs, [token.contract?.address!, token.tokenId]) + const disabled = !isRadio && reachedLimit && !selected + const link = + Utils?.resolveNonFungibleTokenLink && token.contract + ? Utils.resolveNonFungibleTokenLink( + token.contract?.chainId, + token.contract?.address, + token.tokenId, + ) + : undefined return ( - { - if (disabled) return - toggleItem(token.tokenId) - }}> - - { - if (disabled) return - toggleItem(token.tokenId) - }} - className={classes.checkbox} - checked={selectedIds.includes(token.tokenId)} - /> - + title={`${token.contract?.name} ${formatNFT_TokenId(token.tokenId, 2)}`} + placement="top" + arrow> + 0 && !selected, + })}> + + + + { + if (disabled || !token.contract?.address) return + if (selected) { + toggleItem(null, '') + } else { + toggleItem(token.tokenId, token.contract.address) + } + }} + className={classes.checkbox} + checked={selected} + /> + + ) })} diff --git a/packages/mask/src/plugins/NextID/components/Tip/NFTSection/index.tsx b/packages/mask/src/plugins/NextID/components/Tip/NFTSection/index.tsx index 8232f6a1b325..890b18d2701f 100644 --- a/packages/mask/src/plugins/NextID/components/Tip/NFTSection/index.tsx +++ b/packages/mask/src/plugins/NextID/components/Tip/NFTSection/index.tsx @@ -1,14 +1,17 @@ +import { useNetworkDescriptor, useWeb3State as useWeb3PluginState } from '@masknet/plugin-infra' +import { EMPTY_LIST } from '@masknet/shared-base' import { makeStyles } from '@masknet/theme' -import { ERC721TokenDetailed, useAccount, useERC721TokenDetailedCallback } from '@masknet/web3-shared-evm' -import { useERC721TokenDetailedOwnerList } from '@masknet/web3-providers' -import { Button, FormControl, Typography } from '@mui/material' +import { isSameAddress, useAccount } from '@masknet/web3-shared-evm' +import { Button, CircularProgress, Typography } from '@mui/material' import classnames from 'classnames' -import { FC, HTMLProps, useCallback, useMemo, useState } from 'react' -import { SearchInput } from '../../../../../extension/options-page/DashboardComponents/SearchInput' -import { ERC721ContractSelectPanel } from '../../../../../web3/UI/ERC721ContractSelectPanel' -import { TargetChainIdContext, useTip } from '../../../contexts' -import { NFTList } from './NFTList' +import { uniqWith } from 'lodash-unified' +import { FC, HTMLProps, useEffect, useMemo, useState } from 'react' +import { useAsyncFn, useTimeoutFn } from 'react-use' +import { WalletMessages } from '../../../../Wallet/messages' +import { useTip } from '../../../contexts' import { useI18N } from '../../../locales' +import type { TipNFTKeyPair } from '../../../types' +import { NFTList } from './NFTList' export * from './NFTList' @@ -17,36 +20,28 @@ const useStyles = makeStyles()((theme) => ({ display: 'flex', flexDirection: 'column', overflow: 'auto', + height: 282, }, selectSection: { - marginTop: theme.spacing(1.5), display: 'flex', flexDirection: 'column', overflow: 'auto', }, + statusBox: { + display: 'flex', + flexDirection: 'column', + alignItems: 'center', + justifyContent: 'center', + height: 282, + }, + loadingText: { + marginTop: theme.spacing(1), + }, list: { flexGrow: 1, - marginTop: theme.spacing(2), - display: 'grid', - gridTemplateColumns: 'repeat(4, 1fr)', maxHeight: 400, overflow: 'auto', - gridGap: 18, - backgroundColor: theme.palette.background.default, borderRadius: 4, - padding: theme.spacing(1), - }, - keyword: { - borderRadius: 8, - marginRight: theme.spacing(1.5), - }, - searchButton: { - borderRadius: 8, - width: 100, - }, - row: { - display: 'flex', - flexDirection: 'row', }, errorMessage: { marginTop: theme.spacing(3), @@ -56,74 +51,103 @@ const useStyles = makeStyles()((theme) => ({ }, })) -interface Props extends HTMLProps {} +interface Props extends HTMLProps { + onAddToken?(): void + onEmpty?(empty: boolean): void +} -export const NFTSection: FC = ({ className, ...rest }) => { - const t = useI18N() - const { targetChainId: chainId } = TargetChainIdContext.useContainer() - const { erc721Contract, setErc721Contract, erc721TokenId, setErc721TokenId, isSending } = useTip() - const [tokenId, setTokenId, erc721TokenDetailedCallback] = useERC721TokenDetailedCallback(erc721Contract) +export const NFTSection: FC = ({ className, onAddToken, onEmpty, ...rest }) => { + const { erc721Address, erc721TokenId, setErc721TokenId, setErc721Address } = useTip() const { classes } = useStyles() + const t = useI18N() const account = useAccount() - const { tokenDetailedOwnerList: myTokens = [] } = useERC721TokenDetailedOwnerList(erc721Contract, account) + const selectedPairs: TipNFTKeyPair[] = useMemo( + () => (erc721Address && erc721TokenId ? [[erc721Address, erc721TokenId]] : []), + [erc721TokenId, erc721TokenId], + ) + const { Asset } = useWeb3PluginState() + + const networkDescriptor = useNetworkDescriptor() + + // Cannot get the loading status of fetching via websocket + // loading status of `useAsyncRetry` is not the real status + const [guessLoading, setGuessLoading] = useState(true) + useTimeoutFn(() => { + setGuessLoading(false) + }, 10000) + + const [{ value = { data: EMPTY_LIST }, loading }, fetchTokens] = useAsyncFn(async () => { + const result = await Asset?.getNonFungibleAssets?.(account, { page: 0 }, undefined, networkDescriptor) + return result + }, [account, Asset?.getNonFungibleAssets, networkDescriptor]) + + useEffect(() => { + fetchTokens() + }, [fetchTokens]) + + useEffect(() => { + const unsubscribeTokens = WalletMessages.events.erc721TokensUpdated.on(fetchTokens) + const unsubscribeSocket = WalletMessages.events.socketMessageUpdated.on((info) => { + setGuessLoading(info.done) + if (!info.done) { + fetchTokens() + } + }) + return () => { + unsubscribeTokens() + unsubscribeSocket() + } + }, [fetchTokens]) + + const fetchedTokens = value?.data ?? EMPTY_LIST - const selectedIds = useMemo(() => (erc721TokenId ? [erc721TokenId] : []), [erc721TokenId]) + const tokens = useMemo(() => { + return uniqWith(fetchedTokens, (v1, v2) => { + return isSameAddress(v1.contract?.address, v2.contract?.address) && v1.tokenId === v2.tokenId + }) + }, [fetchedTokens]) - const [searchedToken, setSearchedToken] = useState(null) - const onSearch = useCallback(async () => { - const token = await erc721TokenDetailedCallback() - setSearchedToken(token?.info.owner ? token : null) - }, [erc721TokenDetailedCallback]) + const showLoadingIndicator = tokens.length === 0 && !loading && !guessLoading - const tokens = useMemo(() => (searchedToken ? [searchedToken] : myTokens), [searchedToken, myTokens]) - const enableTokenIds = useMemo(() => myTokens.map((t) => t.tokenId), [myTokens]) + useEffect(() => { + onEmpty?.(showLoadingIndicator) + }, [onEmpty, showLoadingIndicator]) return (
- - - - {erc721Contract ? ( -
- - setTokenId(id)} - inputBaseProps={{ - disabled: isSending, - }} - label="" - /> - - - { - setErc721TokenId(ids.length ? ids[0] : null) - }} - /> -
- ) : null} - {tokens.length === 1 && !enableTokenIds.includes(tokens[0].tokenId) ? ( - - {t.nft_not_belong_to_you()} - - ) : null} +
+ {(() => { + if (tokens.length) { + return ( + { + setErc721TokenId(id) + setErc721Address(address) + }} + /> + ) + } + if (loading || guessLoading) { + return ( +
+ + {t.tip_loading()} +
+ ) + } + return ( +
+ {t.tip_empty_nft()} + +
+ ) + })()} +
) } diff --git a/packages/mask/src/plugins/NextID/components/Tip/TipDialog.tsx b/packages/mask/src/plugins/NextID/components/Tip/TipDialog.tsx index aa6a349703ba..12945c87e5e1 100644 --- a/packages/mask/src/plugins/NextID/components/Tip/TipDialog.tsx +++ b/packages/mask/src/plugins/NextID/components/Tip/TipDialog.tsx @@ -1,22 +1,45 @@ -import { SuccessIcon } from '@masknet/icons' -import { PluginId, useActivatedPlugin, useCurrentWeb3NetworkPluginID } from '@masknet/plugin-infra' -import { InjectedDialog, NFTCardStyledAssetPlayer } from '@masknet/shared' +import { Drop2Icon, LinkOutIcon, SuccessIcon } from '@masknet/icons' +import { + PluginId, + useActivatedPlugin, + useCurrentWeb3NetworkPluginID, + useNetworkDescriptor, + useProviderDescriptor, + useReverseAddress, + useWeb3State, +} from '@masknet/plugin-infra' +import { InjectedDialog, NFTCardStyledAssetPlayer, WalletIcon } from '@masknet/shared' import { EMPTY_LIST } from '@masknet/shared-base' -import { openWindow } from '@masknet/shared-base-ui' +import { useRemoteControlledDialog } from '@masknet/shared-base-ui' import { makeStyles } from '@masknet/theme' -import { TransactionStateType, useChainId, useERC721TokenDetailed } from '@masknet/web3-shared-evm' -import { DialogContent, Typography } from '@mui/material' +import { + ERC721TokenDetailed, + TransactionStateType, + useAccount, + useChainId, + useERC721TokenDetailed, +} from '@masknet/web3-shared-evm' +import { DialogContent, Link, Typography } from '@mui/material' import { useCallback, useEffect, useMemo } from 'react' import { useBoolean } from 'react-use' +import { hasNativeAPI, nativeAPI } from '../../../../../shared/native-rpc' import { NetworkTab } from '../../../../components/shared/NetworkTab' import { activatedSocialNetworkUI } from '../../../../social-network' +import { WalletMessages } from '../../../Wallet/messages' import { TargetChainIdContext, useTip } from '../../contexts' import { useI18N } from '../../locales' import { TipType } from '../../types' import { ConfirmModal } from '../ConfirmModal' +import { AddDialog } from './AddDialog' import { TipForm } from './TipForm' const useStyles = makeStyles()((theme) => ({ + dialog: { + width: 600, + }, + dialogTitle: { + height: 60, + }, content: { display: 'flex', flexDirection: 'column', @@ -69,6 +92,53 @@ const useStyles = makeStyles()((theme) => ({ width: 64, height: 64, }, + walletChip: { + marginLeft: 'auto', + height: 40, + boxSizing: 'border-box', + display: 'flex', + alignItems: 'center', + backgroundColor: theme.palette.background.default, + padding: theme.spacing(0.5, 1), + borderRadius: 99, + }, + wallet: { + marginLeft: theme.spacing(1), + }, + walletTitle: { + marginLeft: theme.spacing(1), + lineHeight: '18px', + height: 18, + fontSize: 14, + fontWeight: 'bold', + }, + walletAddress: { + height: 12, + display: 'flex', + alignItems: 'center', + fontSize: 10, + color: theme.palette.text.secondary, + }, + changeWalletButton: { + marginLeft: theme.spacing(0.5), + display: 'flex', + alignItems: 'center', + cursor: 'pointer', + }, + link: { + cursor: 'pointer', + lineHeight: '10px', + marginTop: 2, + '&:hover': { + textDecoration: 'none', + }, + }, + linkIcon: { + fill: 'none', + width: 12, + height: 12, + marginLeft: theme.spacing(0.5), + }, })) interface TipDialogProps { @@ -83,12 +153,25 @@ export function TipDialog({ open = false, onClose }: TipDialogProps) { const t = useI18N() const { classes } = useStyles() + const [addTokenDialogIsOpen, openAddTokenDialog] = useBoolean(false) const [confirmModalIsOpen, openConfirmModal] = useBoolean(false) const { targetChainId, setTargetChainId } = TargetChainIdContext.useContainer() - const { tipType, amount, token, recipientSnsId, recipient, sendState, erc721Contract, erc721TokenId } = useTip() + const { + tipType, + amount, + token, + recipientSnsId, + recipient, + sendState, + erc721Contract, + erc721TokenId, + setErc721Address, + setErc721TokenId, + reset, + } = useTip() const isTokenTip = tipType === TipType.Token - const shareLink = useMemo(() => { + const shareText = useMemo(() => { const promote = t.tip_mask_promote() const message = isTokenTip ? t.tip_token_share_post({ @@ -99,12 +182,12 @@ export function TipDialog({ open = false, onClose }: TipDialogProps) { promote, }) : t.tip_nft_share_post({ - name: erc721Contract?.name || '', + name: erc721Contract?.name || 'NFT', recipientSnsId, recipient, promote, }) - return activatedSocialNetworkUI.utils.getShareLinkURL?.(message) + return message }, [amount, isTokenTip, erc721Contract?.name, token, recipient, recipientSnsId, t]) const { tokenDetailed: erc721Token } = useERC721TokenDetailed(erc721Contract, erc721TokenId) @@ -143,14 +226,68 @@ export function TipDialog({ open = false, onClose }: TipDialogProps) { }, [sendState.type]) const handleConfirm = useCallback(() => { - openWindow(shareLink) + activatedSocialNetworkUI.utils.share?.(shareText) openConfirmModal(false) onClose?.() - }, [shareLink, onClose]) + }, [shareText, onClose]) + const networkDescriptor = useNetworkDescriptor() + const providerDescriptor = useProviderDescriptor() + + const { Utils } = useWeb3State() + const account = useAccount() + const { value: domain } = useReverseAddress(account) + const walletTitle = + Utils?.formatDomainName?.(domain) || Utils?.formatAddress?.(account, 4) || providerDescriptor?.name + + // #region change provider + const { openDialog: openSelectProviderDialog } = useRemoteControlledDialog( + WalletMessages.events.selectProviderDialogUpdated, + ) + // #endregion + const openWallet = useCallback(() => { + if (hasNativeAPI) return nativeAPI?.api.misc_openCreateWalletView() + return openSelectProviderDialog() + }, [openSelectProviderDialog, hasNativeAPI]) + + const handleAddToken = useCallback((token: ERC721TokenDetailed) => { + setErc721Address(token.contractDetailed.address ?? '') + setErc721TokenId(token.tokenId) + openAddTokenDialog(false) + }, []) + + const walletChip = account ? ( +
+ +
+ + {walletTitle} + + + + {Utils?.formatAddress?.(account, 4)} + + + + +
+
+ +
+
+ ) : null return ( <> - +
- + openAddTokenDialog(true)} />
openConfirmModal(false)} + onClose={() => { + openConfirmModal(false) + reset() + onClose?.() + }} icon={isTokenTip ? : null} message={successMessage} confirmText={t.tip_share()} onConfirm={handleConfirm} /> + openAddTokenDialog(false)} onAdd={handleAddToken} /> ) } diff --git a/packages/mask/src/plugins/NextID/components/Tip/TipForm.tsx b/packages/mask/src/plugins/NextID/components/Tip/TipForm.tsx index b8c731e49afd..d0f947d54542 100644 --- a/packages/mask/src/plugins/NextID/components/Tip/TipForm.tsx +++ b/packages/mask/src/plugins/NextID/components/Tip/TipForm.tsx @@ -1,17 +1,29 @@ import { useWeb3State } from '@masknet/plugin-infra' import { WalletMessages } from '@masknet/plugin-wallet' -import { usePickToken } from '@masknet/shared' import { useRemoteControlledDialog } from '@masknet/shared-base-ui' import { makeStyles } from '@masknet/theme' -import { EthereumTokenType, useAccount, useFungibleTokenBalance } from '@masknet/web3-shared-evm' -import { Box, BoxProps, FormControl, MenuItem, Select, Typography } from '@mui/material' +import { ChainId, useAccount, useChainId } from '@masknet/web3-shared-evm' +import { + Box, + BoxProps, + Button, + FormControl, + FormControlLabel, + MenuItem, + Radio, + RadioGroup, + Select, + Typography, +} from '@mui/material' import classnames from 'classnames' -import { FC, memo, useCallback, useRef } from 'react' +import { FC, memo, useRef, useState } from 'react' import ActionButton from '../../../../extension/options-page/DashboardComponents/ActionButton' import { EthereumChainBoundary } from '../../../../web3/UI/EthereumChainBoundary' -import { TokenAmountPanel } from '../../../../web3/UI/TokenAmountPanel' import { TargetChainIdContext, useTip, useTipValidate } from '../../contexts' import { useI18N } from '../../locales' +import { TipType } from '../../types' +import { NFTSection } from './NFTSection' +import { TokenSection } from './TokenSection' const useStyles = makeStyles()((theme) => { return { @@ -25,6 +37,20 @@ const useStyles = makeStyles()((theme) => { flexGrow: 1, overflow: 'auto', }, + receiverRow: { + display: 'flex', + flexDirection: 'row', + alignItems: 'center', + }, + to: { + fontSize: 19, + fontWeight: 500, + }, + address: { + height: 48, + flexGrow: 1, + marginLeft: theme.spacing(1), + }, actionButton: { marginTop: theme.spacing(1.5), fontSize: 16, @@ -47,28 +73,37 @@ const useStyles = makeStyles()((theme) => { borderRadius: 24, height: 'auto', }, + controls: { + marginTop: theme.spacing(1), + display: 'flex', + flexDirection: 'row', + }, + addButton: { + marginLeft: 'auto', + }, tokenField: { marginTop: theme.spacing(2), }, } }) -interface Props extends BoxProps {} +interface Props extends BoxProps { + onAddToken?(): void +} -export const TipForm: FC = memo(({ className, ...rest }) => { +export const TipForm: FC = memo(({ className, onAddToken, ...rest }) => { const t = useI18N() + const currentChainId = useChainId() const { targetChainId: chainId } = TargetChainIdContext.useContainer() const { classes } = useStyles() const { recipient, recipients: recipientAddresses, setRecipient, - token, - setToken, - amount, - setAmount, isSending, sendTip, + tipType, + setTipType, } = useTip() const [isValid, validateMessage] = useTipValidate() const { Utils } = useWeb3State() @@ -77,35 +112,21 @@ export const TipForm: FC = memo(({ className, ...rest }) => { const { openDialog: openSelectProviderDialog } = useRemoteControlledDialog( WalletMessages.events.selectProviderDialogUpdated, ) - const pickToken = usePickToken() - const onSelectTokenChipClick = useCallback(async () => { - const picked = await pickToken({ - chainId, - disableNativeToken: false, - selectedTokens: token ? [token.address] : [], - }) - if (picked) { - setToken(picked) - } - }, [pickToken, token?.address, chainId]) - - // balance - const { value: tokenBalance = '0', loading: loadingTokenBalance } = useFungibleTokenBalance( - token?.type || EthereumTokenType.Native, - token?.address || '', - chainId, - ) - // #endregion + const [empty, setEmpty] = useState(false) const buttonLabel = isSending ? t.sending_tip() : isValid || !validateMessage ? t.send_tip() : validateMessage + const enabledNft = + !isSending && + chainId === currentChainId && + [ChainId.Mainnet, ChainId.BSC, ChainId.Matic].includes(currentChainId) return (
- {t.tip_to()} - - + + {t.tip_to()} - - + + setTipType(e.target.value as TipType)}> + } + label={t.tip_type_token()} + /> + } + label={t.tip_type_nft()} + /> + + {tipType === TipType.NFT && !empty ? ( + + ) : null} + {tipType === TipType.Token ? ( + + + + ) : ( + + )}
{account ? ( { + const { token, setToken, amount, setAmount, isSending } = useTip() + const { targetChainId: chainId } = TargetChainIdContext.useContainer() + // balance + const { value: tokenBalance = '0', loading: loadingTokenBalance } = useFungibleTokenBalance( + token?.type || EthereumTokenType.Native, + token?.address || '', + chainId, + ) + const gasConfig = useGasConfig(chainId) + const maxAmount = useMemo(() => { + if (!isNativeTokenAddress(token?.address)) return tokenBalance + const gasPrice = gasConfig.gasPrice ?? '1' + const gasFee = new BigNumber(gasPrice).times(GAS_LIMIT) + return new BigNumber(tokenBalance).minus(gasFee).toFixed() + }, [token?.address, tokenBalance, gasConfig.gasPrice]) + const pickToken = usePickToken() + const onSelectTokenChipClick = useCallback(async () => { + const picked = await pickToken({ + chainId, + disableNativeToken: false, + selectedTokens: token ? [token.address] : [], + }) + if (picked) { + setToken(picked) + } + }, [pickToken, token?.address, chainId]) + // #endregion + return ( + + ) +} diff --git a/packages/mask/src/plugins/NextID/contexts/TargetChainIdContext.ts b/packages/mask/src/plugins/NextID/contexts/TargetChainIdContext.ts index 17df3f66514f..ad2d904a03a7 100644 --- a/packages/mask/src/plugins/NextID/contexts/TargetChainIdContext.ts +++ b/packages/mask/src/plugins/NextID/contexts/TargetChainIdContext.ts @@ -1,11 +1,15 @@ import { ChainId, useChainId } from '@masknet/web3-shared-evm' -import { useState } from 'react' +import { useEffect, useState } from 'react' import { createContainer } from 'unstated-next' function useTargetChainId() { const chainId = useChainId() const [targetChainId, setTargetChainId] = useState(chainId) + useEffect(() => { + setTargetChainId(chainId) + }, [chainId]) + return { targetChainId, setTargetChainId, diff --git a/packages/mask/src/plugins/NextID/contexts/Tip/TipContext.ts b/packages/mask/src/plugins/NextID/contexts/Tip/TipContext.ts index 2082cac59765..8fa4be5af260 100644 --- a/packages/mask/src/plugins/NextID/contexts/Tip/TipContext.ts +++ b/packages/mask/src/plugins/NextID/contexts/Tip/TipContext.ts @@ -1,3 +1,4 @@ +import type { Web3Plugin } from '@masknet/plugin-infra' import { ERC721ContractDetailed, FungibleTokenDetailed, @@ -22,10 +23,13 @@ export interface ContextOptions { erc721TokenId: string | null setErc721TokenId: Dispatch> erc721Contract: ERC721ContractDetailed | null - setErc721Contract: Dispatch> + erc721Address: string + setErc721Address: Dispatch> sendTip: () => Promise isSending: boolean sendState: TransactionState + storedTokens: Web3Plugin.NonFungibleToken[] + reset: () => void } export const TipContext = createContext({ @@ -42,8 +46,11 @@ export const TipContext = createContext({ erc721TokenId: null, setErc721TokenId: noop, erc721Contract: null, - setErc721Contract: noop, + erc721Address: '', + setErc721Address: noop, sendTip: noop as () => Promise, isSending: false, sendState: { type: TransactionStateType.UNKNOWN }, + storedTokens: [], + reset: noop, }) diff --git a/packages/mask/src/plugins/NextID/contexts/Tip/TipTaskProvider.tsx b/packages/mask/src/plugins/NextID/contexts/Tip/TipTaskProvider.tsx index de39fd31f565..7b8722fa717e 100644 --- a/packages/mask/src/plugins/NextID/contexts/Tip/TipTaskProvider.tsx +++ b/packages/mask/src/plugins/NextID/contexts/Tip/TipTaskProvider.tsx @@ -1,5 +1,12 @@ -import { TransactionStateType, useNativeTokenDetailed } from '@masknet/web3-shared-evm' +import { + TransactionStateType, + useChainId, + useERC721ContractDetailed, + useNativeTokenDetailed, +} from '@masknet/web3-shared-evm' import { FC, useContext, useEffect, useMemo, useState } from 'react' +import { useSubscription } from 'use-subscription' +import { getStorage } from '../../storage' import { TipTask, TipType } from '../../types' import { TargetChainIdContext } from '../TargetChainIdContext' import { ContextOptions, TipContext } from './TipContext' @@ -15,10 +22,14 @@ export const TipTaskProvider: FC = ({ children, task }) => { const [tipType, setTipType] = useState(TipType.Token) const [amount, setAmount] = useState('') const { targetChainId } = TargetChainIdContext.useContainer() - const [erc721Contract, setErc721Contract] = useState(null) + const chainId = useChainId() + const [erc721Address, setErc721Address] = useState('') const { value: nativeTokenDetailed = null } = useNativeTokenDetailed(targetChainId) const [token, setToken] = useState(nativeTokenDetailed) const [erc721TokenId, setErc721TokenId] = useState(null) + const storedTokens = useSubscription(getStorage().addedTokens.subscription) + + const { value: erc721Contract } = useERC721ContractDetailed(erc721Address) useEffect(() => { setTipType(TipType.Token) @@ -38,7 +49,7 @@ export const TipTaskProvider: FC = ({ children, task }) => { setToken(nativeTokenDetailed) }, [nativeTokenDetailed]) const tokenTipTuple = useTokenTip(recipient, token, amount) - const nftTipTuple = useNftTip(recipient, erc721TokenId, erc721Contract) + const nftTipTuple = useNftTip(recipient, erc721TokenId, erc721Address) const sendTipTuple = tipType === TipType.Token ? tokenTipTuple : nftTipTuple const sendState = sendTipTuple[0] @@ -51,6 +62,12 @@ export const TipTaskProvider: FC = ({ children, task }) => { TransactionStateType.RECEIPT, ].includes(sendState.type) + const reset = () => { + setAmount('') + setErc721TokenId(null) + setErc721Address('') + } + return { recipient, recipientSnsId: task.recipientSnsId || '', @@ -64,13 +81,17 @@ export const TipTaskProvider: FC = ({ children, task }) => { setAmount, erc721TokenId, setErc721TokenId, - erc721Contract, - setErc721Contract, + erc721Contract: erc721Contract || null, + erc721Address, + setErc721Address, sendTip, isSending, sendState, + storedTokens: storedTokens.filter((t) => t.contract?.chainId === chainId), + reset, } }, [ + chainId, recipient, task.recipientSnsId, task.addresses, @@ -78,9 +99,11 @@ export const TipTaskProvider: FC = ({ children, task }) => { amount, erc721TokenId, erc721Contract, + erc721Address, token, sendTip, sendState, + storedTokens, ]) return {children} } diff --git a/packages/mask/src/plugins/NextID/contexts/Tip/useNftTip.ts b/packages/mask/src/plugins/NextID/contexts/Tip/useNftTip.ts index 398d2cfbe769..da0a1a620572 100644 --- a/packages/mask/src/plugins/NextID/contexts/Tip/useNftTip.ts +++ b/packages/mask/src/plugins/NextID/contexts/Tip/useNftTip.ts @@ -1,21 +1,32 @@ -import { ERC721ContractDetailed, EthereumTokenType, useTokenTransferCallback } from '@masknet/web3-shared-evm' -import { useCallback } from 'react' +import { + EthereumTokenType, + useERC721ContractDetailed, + useERC721TokenDetailedCallback, + useTokenTransferCallback, +} from '@masknet/web3-shared-evm' +import { useCallback, useEffect } from 'react' +import { WalletRPC } from '../../../Wallet/messages' import type { TipTuple } from './type' -export function useNftTip( - recipient: string, - tokenId: string | null, - contract: ERC721ContractDetailed | null, -): TipTuple { - const [transferState, transferCallback] = useTokenTransferCallback( - EthereumTokenType.ERC721, - contract?.address || '', - ) +export function useNftTip(recipient: string, tokenId: string | null, contractAddress?: string): TipTuple { + const [transferState, transferCallback] = useTokenTransferCallback(EthereumTokenType.ERC721, contractAddress || '') + const { value: contractDetailed } = useERC721ContractDetailed(contractAddress) + const [, setTokenId, erc721TokenDetailedCallback] = useERC721TokenDetailedCallback(contractDetailed) + + useEffect(() => { + if (tokenId) { + setTokenId(tokenId) + } + }, [tokenId]) const sendTip = useCallback(async () => { - if (!tokenId) return + if (!tokenId || !contractAddress) return await transferCallback(tokenId, recipient) - }, [tokenId, recipient, transferCallback]) + const tokenDetailed = await erc721TokenDetailedCallback() + if (tokenDetailed) { + await WalletRPC.removeToken(tokenDetailed) + } + }, [tokenId, contractAddress, erc721TokenDetailedCallback, recipient, transferCallback]) return [transferState, sendTip] } diff --git a/packages/mask/src/plugins/NextID/contexts/Tip/useTipValidate.ts b/packages/mask/src/plugins/NextID/contexts/Tip/useTipValidate.ts index 741010377f9c..2eca80b4dc8d 100644 --- a/packages/mask/src/plugins/NextID/contexts/Tip/useTipValidate.ts +++ b/packages/mask/src/plugins/NextID/contexts/Tip/useTipValidate.ts @@ -8,7 +8,7 @@ import { TipContext } from './TipContext' type ValidationTuple = [isValid: boolean, message?: string] export function useTipValidate(): ValidationTuple { - const { tipType, amount, token, erc721TokenId, erc721Contract } = useContext(TipContext) + const { tipType, amount, token, erc721TokenId, erc721Address } = useContext(TipContext) const { value: balance = '0' } = useFungibleTokenBalance(token?.type || EthereumTokenType.Native, token?.address) const t = useI18N() @@ -18,10 +18,10 @@ export function useTipValidate(): ValidationTuple { if (isGreaterThan(rightShift(amount, token?.decimals), balance)) return [false, t.token_insufficient_balance()] } else { - if (!erc721TokenId || !erc721Contract) return [false] + if (!erc721TokenId || !erc721Address) return [false] } return [true] - }, [tipType, amount, token?.decimals, balance, erc721Contract, erc721TokenId, t]) + }, [tipType, amount, token?.decimals, balance, erc721TokenId, erc721Address, t]) return result } diff --git a/packages/mask/src/plugins/NextID/locales/en-US.json b/packages/mask/src/plugins/NextID/locales/en-US.json index a9b3f95a04e6..fda218ebf57a 100644 --- a/packages/mask/src/plugins/NextID/locales/en-US.json +++ b/packages/mask/src/plugins/NextID/locales/en-US.json @@ -53,8 +53,8 @@ "send_tip": "Send", "sending_tip": "Sending...", "nft_not_belong_to_you": "The collectible doesn't exist or belong to you.", - "send_tip_successfully": "Sent tip successfully", - "send_specific_tip_successfully": "Sent {{amount}} {{name}} tip successfully", + "send_tip_successfully": "Sent tip successfully.", + "send_specific_tip_successfully": "Sent {{amount}} {{name}} tip successfully.", "tip_share": "Share", "tip_connect_wallet_message": "Please connect to a wallet.", "tip_connect_wallet": "Connect Wallet", @@ -62,5 +62,13 @@ "tip_contracts": "Contracts", "tip_mask_promote": "Install https://mask.io/download-links to send your first tip.", "tip_token_share_post": "I just tipped {{amount}} {{symbol}} to @{{recipientSnsId}}'s wallet address {{recipient}}\n\n{{promote}}", - "tip_nft_share_post": "I just tipped a {{name}} to @{{recipientSnsId}}'s wallet address {{recipient}}\n\n{{promote}}" + "tip_nft_share_post": "I just tipped a {{name}} to @{{recipientSnsId}}'s wallet address {{recipient}}\n\n{{promote}}", + "tip_add": "Add", + "tip_adding": "Adding", + "tip_add_collectibles": "Add Collectibles", + "tip_add_collectibles_contract_address": "Input contract address", + "tip_add_collectibles_token_id": "Token ID", + "tip_add_collectibles_error": "The contract address is incorrect or the collectible does not belong to you.", + "tip_loading": "Loading", + "tip_empty_nft": "No any collectible is available to preview. Please add your collectible here." } diff --git a/packages/mask/src/plugins/NextID/storage/index.ts b/packages/mask/src/plugins/NextID/storage/index.ts new file mode 100644 index 000000000000..6c9312b13e59 --- /dev/null +++ b/packages/mask/src/plugins/NextID/storage/index.ts @@ -0,0 +1,38 @@ +import type { Web3Plugin } from '@masknet/plugin-infra' +import type { ScopedStorage } from '@masknet/shared-base' +import { isSameAddress } from '@masknet/web3-shared-evm' +import { remove } from 'lodash-unified' + +interface StorageValue { + addedTokens: Web3Plugin.NonFungibleToken[] +} + +export const storageDefaultValue = { + publicKey: null as null | string, + addedTokens: [], +} + +let storage: ScopedStorage = null! + +export function setupStorage(_: typeof storage) { + storage = _ +} + +export function getStorage() { + return storage.storage +} + +export function getTokens() { + return storage.storage.addedTokens.value +} + +export function storeToken(token: Web3Plugin.NonFungibleToken) { + const tokens = [token, ...getTokens()] + storage.storage.addedTokens.setValue(tokens) +} + +export function deleteToken(address: string, tokenId: string) { + const tokens = getTokens() + remove(tokens, (t) => t.tokenId === tokenId && isSameAddress(t.contract?.address, address)) + storage.storage.addedTokens.setValue(tokens) +} diff --git a/packages/mask/src/plugins/NextID/types/tip.ts b/packages/mask/src/plugins/NextID/types/tip.ts index 2e6cbde0e5cd..8fefaf25e33a 100644 --- a/packages/mask/src/plugins/NextID/types/tip.ts +++ b/packages/mask/src/plugins/NextID/types/tip.ts @@ -8,3 +8,5 @@ export interface TipTask { recipientSnsId?: string addresses: string[] } + +export type TipNFTKeyPair = [address: string, tokenId: string] diff --git a/packages/plugin-infra/src/web3-types.ts b/packages/plugin-infra/src/web3-types.ts index d851716caf51..5c1442031d6b 100644 --- a/packages/plugin-infra/src/web3-types.ts +++ b/packages/plugin-infra/src/web3-types.ts @@ -29,6 +29,18 @@ export type Color = | `#${string}${string}${string}` | `hsl(${number}, ${number}%, ${number}%)` +// Borrow from @masknet/web3-shared-evm +interface ERC721TokenInfo { + name?: string + description?: string + tokenURI?: string + mediaUrl?: string + imageURL?: string + owner?: string + // loading tokenURI + hasTokenDetailed?: boolean +} + export declare namespace Web3Plugin { /** * Plugin can declare what chain it supports to trigger side effects (e.g. create a new transaction). @@ -197,6 +209,7 @@ export declare namespace Web3Plugin { description?: string owner?: string metadata?: NonFungibleTokenMetadata + info?: ERC721TokenInfo contract?: NonFungibleContract } diff --git a/packages/shared/src/UI/components/AssetPlayer/index.tsx b/packages/shared/src/UI/components/AssetPlayer/index.tsx index 08ce050d74b1..ed4b076351a1 100644 --- a/packages/shared/src/UI/components/AssetPlayer/index.tsx +++ b/packages/shared/src/UI/components/AssetPlayer/index.tsx @@ -163,10 +163,7 @@ export const AssetPlayer = memo((props) => { setIframe() }} className={ - ![ - AssetPlayerState.NORMAL, - ...(props.showIframeFromInit ? [AssetPlayerState.INIT] : []), - ].includes(playerState) + ![AssetPlayerState.NORMAL, AssetPlayerState.INIT].includes(playerState) ? classes.hidden : classes.iframe } diff --git a/packages/shared/src/UI/components/ImageIcon/index.tsx b/packages/shared/src/UI/components/ImageIcon/index.tsx index 90110f420a1d..5a020afcee7b 100644 --- a/packages/shared/src/UI/components/ImageIcon/index.tsx +++ b/packages/shared/src/UI/components/ImageIcon/index.tsx @@ -8,7 +8,7 @@ const useStyles = makeStyles()((theme) => { export interface ImageIconProps extends withClasses<'icon'> { size?: number - icon?: URL + icon?: URL | string } export function ImageIcon(props: ImageIconProps) { diff --git a/packages/shared/src/UI/components/NFTCardStyledAssetPlayer/index.tsx b/packages/shared/src/UI/components/NFTCardStyledAssetPlayer/index.tsx index 2aeb6adc0757..ac2bea3ed059 100644 --- a/packages/shared/src/UI/components/NFTCardStyledAssetPlayer/index.tsx +++ b/packages/shared/src/UI/components/NFTCardStyledAssetPlayer/index.tsx @@ -13,9 +13,6 @@ const useStyles = makeStyles()((theme) => ({ width: 120, overflow: 'hidden', }, - loadingNftImg: { - marginTop: 20, - }, loadingPlaceholder: { height: 160, width: 120, @@ -45,6 +42,10 @@ interface Props extends withClasses<'loadingFailImage' | 'iframe' | 'wrapper' | setERC721TokenName?: (name: string) => void setSourceType?: (type: string) => void } + +const assetPlayerFallbackImageDark = new URL('./nft_token_fallback_dark.png', import.meta.url) +const assetPlayerFallbackImageLight = new URL('./nft_token_fallback.png', import.meta.url) + export function NFTCardStyledAssetPlayer(props: Props) { const { chainId = ChainId.Mainnet, @@ -67,9 +68,7 @@ export function NFTCardStyledAssetPlayer(props: Props) { const { value: isImageToken } = useImageChecker(url || tokenDetailed?.info.imageURL || tokenDetailed?.info.mediaUrl) const fallbackImageURL = - theme.palette.mode === 'dark' - ? new URL('./nft_token_fallback_dark.png', import.meta.url) - : new URL('./nft_token_fallback.png', import.meta.url) + theme.palette.mode === 'dark' ? assetPlayerFallbackImageDark : assetPlayerFallbackImageLight return isImageToken || isNative ? (
@@ -86,6 +85,7 @@ export function NFTCardStyledAssetPlayer(props: Props) {
) : ( 200) iframe at once. renderTimeout={renderOrder ? 20000 * Math.floor(renderOrder / 100) : undefined} fallbackImage={fallbackImage ?? fallbackImageURL} - loadingIcon={} + loadingIcon={} classes={{ iframe: classNames(classes.wrapper, classes.iframe), errorPlaceholder: classes.wrapper, diff --git a/packages/shared/src/contexts/components/InjectedDialog.tsx b/packages/shared/src/contexts/components/InjectedDialog.tsx index 9e55e3a89039..99355b9cac55 100644 --- a/packages/shared/src/contexts/components/InjectedDialog.tsx +++ b/packages/shared/src/contexts/components/InjectedDialog.tsx @@ -54,6 +54,7 @@ export interface InjectedDialogProps extends Omit> onClose?(): void title?: React.ReactChild + titleTail?: React.ReactChild | null disableBackdropClick?: boolean disableTitleBorder?: boolean titleBarIconStyle?: 'auto' | 'back' | 'close' @@ -78,8 +79,17 @@ export function InjectedDialog(props: InjectedDialogProps) { const t = useSharedI18N() const fullScreen = useMediaQuery(useTheme().breakpoints.down('xs')) const isDashboard = isDashboardPage() - const { children, open, disableBackdropClick, titleBarIconStyle, onClose, title, disableTitleBorder, ...rest } = - props + const { + children, + open, + disableBackdropClick, + titleBarIconStyle, + onClose, + title, + titleTail = null, + disableTitleBorder, + ...rest + } = props const actions = CopyElementWithNewProps(children, DialogActions, { root: dialogActions }) const content = CopyElementWithNewProps(children, DialogContent, { root: dialogContent }) const { extraProps, shouldReplaceExitWithBack, IncreaseStack } = useDialogStackActor(open) @@ -128,6 +138,7 @@ export function InjectedDialog(props: InjectedDialogProps) { {title} + {titleTail} ) : null} {/* There is a .MuiDialogTitle+.MuiDialogContent selector that provides paddingTop: 0 */} diff --git a/packages/web3-shared/evm/hooks/useERC721ContractDetailed.ts b/packages/web3-shared/evm/hooks/useERC721ContractDetailed.ts index 4ca404e8db20..c99f91b9e31b 100644 --- a/packages/web3-shared/evm/hooks/useERC721ContractDetailed.ts +++ b/packages/web3-shared/evm/hooks/useERC721ContractDetailed.ts @@ -5,39 +5,14 @@ import type { ChainId } from '../types' import { useChainId } from './useChainId' import { useERC721TokenContract } from '../contracts/useERC721TokenContract' import { createERC721ContractDetailed, safeNonPayableTransactionCall } from '../utils' -import { useOpenseaAPIConstants } from '../constants' +import { getOpenseaAPIConstants } from '../constants' export function useERC721ContractDetailed(address?: string) { const chainId = useChainId() - const { GET_CONTRACT_URL } = useOpenseaAPIConstants() const erc721TokenContract = useERC721TokenContract(address) return useAsyncRetry(async () => { if (!address || !EthereumAddress.isValid(address) || !erc721TokenContract) return - - const erc721ContractDetailedFromChain = await getERC721ContractDetailedFromChain( - address, - chainId, - erc721TokenContract, - ) - - if (!GET_CONTRACT_URL) return erc721ContractDetailedFromChain - - const contractDetailedFromOpensea = await getERC721ContractDetailedFromOpensea( - address, - chainId, - GET_CONTRACT_URL, - ) - - // We prefer to use `name` and `symbol` from chain rather than opensea since, - // these two data on opensea is sometimes incorrect. Meanwhile there's often - // a lack of `iconURL` from chain, which exists on opensea. - return contractDetailedFromOpensea - ? { - ...contractDetailedFromOpensea, - name: erc721ContractDetailedFromChain.name, - symbol: erc721ContractDetailedFromChain.symbol, - } - : erc721ContractDetailedFromChain + return getERC721ContractDetailed(erc721TokenContract, address, chainId) }, [address, chainId, erc721TokenContract]) } @@ -69,3 +44,21 @@ async function getERC721ContractDetailedFromOpensea(address: string, chainId: Ch } return null } + +export async function getERC721ContractDetailed(contract: ERC721, address: string, chainId: ChainId) { + const erc721ContractDetailedFromChain = await getERC721ContractDetailedFromChain(address, chainId, contract) + const { GET_CONTRACT_URL } = getOpenseaAPIConstants(chainId) + if (!GET_CONTRACT_URL) return erc721ContractDetailedFromChain + const contractDetailedFromOpensea = await getERC721ContractDetailedFromOpensea(address, chainId, GET_CONTRACT_URL) + + // We prefer to use `name` and `symbol` from chain rather than opensea since, + // these two data on opensea is sometimes incorrect. Meanwhile there's often + // a lack of `iconURL` from chain, which exists on opensea. + return contractDetailedFromOpensea + ? { + ...contractDetailedFromOpensea, + name: erc721ContractDetailedFromChain.name, + symbol: erc721ContractDetailedFromChain.symbol, + } + : erc721ContractDetailedFromChain +} diff --git a/packages/web3-shared/evm/hooks/useERC721TokenDetailed.ts b/packages/web3-shared/evm/hooks/useERC721TokenDetailed.ts index e120f5d5616a..6dd2eb3d033f 100644 --- a/packages/web3-shared/evm/hooks/useERC721TokenDetailed.ts +++ b/packages/web3-shared/evm/hooks/useERC721TokenDetailed.ts @@ -1,37 +1,25 @@ +import type { ERC721 } from '@masknet/web3-contracts/types/ERC721' +import { first, noop } from 'lodash-unified' import { useAsyncRetry } from 'react-use' -import { useRef } from 'react' import urlcat from 'urlcat' -import { first, noop } from 'lodash-unified' -import type { ERC721ContractDetailed, ERC721TokenInfo, ERC721TokenDetailed } from '../types' +import { getOpenseaAPIConstants } from '../constants' import { useERC721TokenContract } from '../contracts/useERC721TokenContract' -import { safeNonPayableTransactionCall, createERC721Token, formatNFT_TokenId } from '../utils' -import type { ERC721 } from '@masknet/web3-contracts/types/ERC721' -import { useOpenseaAPIConstants } from '../constants' +import type { ChainId, ERC721ContractDetailed, ERC721TokenInfo } from '../types' +import { createERC721Token, formatNFT_TokenId, safeNonPayableTransactionCall } from '../utils' +import { useChainId } from './useChainId' export function useERC721TokenDetailed( contractDetailed: ERC721ContractDetailed | null | undefined, tokenId: string | null | undefined, ) { - const { GET_SINGLE_ASSET_URL } = useOpenseaAPIConstants() const erc721TokenContract = useERC721TokenContract(contractDetailed?.address ?? '') - const tokenDetailedRef = useRef() + const chainId = useChainId() const asyncRetry = useAsyncRetry(async () => { if (!erc721TokenContract || !contractDetailed || !tokenId || !contractDetailed.address) return - tokenDetailedRef.current = GET_SINGLE_ASSET_URL - ? await getERC721TokenDetailedFromOpensea(contractDetailed, tokenId, GET_SINGLE_ASSET_URL) - : await getERC721TokenDetailedFromChain(contractDetailed, erc721TokenContract, tokenId) - const info = await getERC721TokenAssetFromChain(tokenDetailedRef.current?.info.tokenURI) - - if (info && tokenDetailedRef.current) - tokenDetailedRef.current.info = { - ...info, - ...tokenDetailedRef.current.info, - hasTokenDetailed: true, - name: info.name ?? tokenDetailedRef.current.info.name, - } - }, [tokenId, JSON.stringify(contractDetailed), erc721TokenContract, GET_SINGLE_ASSET_URL]) + return getERC721TokenDetailed(contractDetailed, erc721TokenContract, tokenId, chainId) + }, [tokenId, JSON.stringify(contractDetailed), erc721TokenContract]) - return { asyncRetry, tokenDetailed: tokenDetailedRef.current } + return { asyncRetry, tokenDetailed: asyncRetry.value } } export async function getERC721TokenDetailedFromOpensea( @@ -142,3 +130,25 @@ export async function getERC721TokenAssetFromChain(tokenURI?: string): Promise { + setTransferState({ + type: TransactionStateType.UNKNOWN, + }) if (!account || !recipient || !tokenId || !erc721Contract) { - setTransferState({ - type: TransactionStateType.UNKNOWN, - }) return } diff --git a/packages/web3-shared/evm/utils/formatter.ts b/packages/web3-shared/evm/utils/formatter.ts index 8a80d99b4564..1c907af9d583 100644 --- a/packages/web3-shared/evm/utils/formatter.ts +++ b/packages/web3-shared/evm/utils/formatter.ts @@ -59,7 +59,7 @@ export function formatEthereumAddress(address: string, size = 0) { } export function formatNFT_TokenId(tokenId: string, size = 0) { - if (tokenId.length < 9) return tokenId + if (tokenId.length < 9) return `#${tokenId}` return `#${tokenId.substr(0, 2 + size)}...${tokenId.substr(-size)}` } From 84acaea46a8d9b233a5b1a1edf988b3a710f8846 Mon Sep 17 00:00:00 2001 From: Randolph314 <97870249+Randolph314@users.noreply.github.com> Date: Wed, 6 Apr 2022 16:21:46 +0800 Subject: [PATCH 30/42] feat: add cross-chain-bridge plugin (#6016) * feat: add cross-chain-bridge plugin * feat: add word ignored * feat: delete useless code * feat: add parameter type * feat: delete useless code and add ID for bridges Co-authored-by: Randolph <840094513@qq.com> --- .i18n-codegen.json | 12 +++ cspell.json | 2 + packages/mask/.webpack/config.ts | 1 + packages/mask/package.json | 3 +- packages/mask/src/plugin-infra/register.js | 1 + packages/plugin-infra/src/types.ts | 1 + packages/plugins/CrossChainBridge/README.md | 5 + .../plugins/CrossChainBridge/package.json | 12 +++ .../CrossChainBridge/src/Dashboard/index.tsx | 9 ++ .../src/SNSAdaptor/CrossChainBridgeDialog.tsx | 99 ++++++++++++++++++ .../src/SNSAdaptor/MaskIcon.tsx | 50 +++++++++ .../SNSAdaptor/assets/arbitrum-one-bridge.png | Bin 0 -> 1845 bytes .../src/SNSAdaptor/assets/boba-bridge.png | Bin 0 -> 3054 bytes .../src/SNSAdaptor/assets/cbridge.png | Bin 0 -> 3949 bytes .../src/SNSAdaptor/assets/cross-chain.png | Bin 0 -> 3527 bytes .../src/SNSAdaptor/assets/polygon-bridge.png | Bin 0 -> 1021 bytes .../src/SNSAdaptor/assets/rainbow-bridge.png | Bin 0 -> 1355 bytes .../CrossChainBridge/src/SNSAdaptor/index.tsx | 31 ++++++ .../CrossChainBridge/src/Worker/index.ts | 9 ++ packages/plugins/CrossChainBridge/src/base.ts | 18 ++++ .../CrossChainBridge/src/constants.tsx | 53 ++++++++++ .../plugins/CrossChainBridge/src/env.d.ts | 1 + .../plugins/CrossChainBridge/src/index.ts | 23 ++++ .../CrossChainBridge/src/locales/en-US.json | 6 ++ .../CrossChainBridge/src/locales/index.ts | 6 ++ .../CrossChainBridge/src/locales/ja-JP.json | 1 + .../CrossChainBridge/src/locales/ko-KR.json | 1 + .../CrossChainBridge/src/locales/languages.ts | 36 +++++++ .../CrossChainBridge/src/locales/qya-AA.json | 4 + .../CrossChainBridge/src/locales/zh-CN.json | 1 + .../CrossChainBridge/src/locales/zh-TW.json | 1 + .../plugins/CrossChainBridge/tsconfig.json | 10 ++ packages/plugins/tsconfig.json | 3 +- pnpm-lock.yaml | 20 +++- tsconfig.json | 1 + 35 files changed, 415 insertions(+), 5 deletions(-) create mode 100644 packages/plugins/CrossChainBridge/README.md create mode 100644 packages/plugins/CrossChainBridge/package.json create mode 100644 packages/plugins/CrossChainBridge/src/Dashboard/index.tsx create mode 100644 packages/plugins/CrossChainBridge/src/SNSAdaptor/CrossChainBridgeDialog.tsx create mode 100644 packages/plugins/CrossChainBridge/src/SNSAdaptor/MaskIcon.tsx create mode 100644 packages/plugins/CrossChainBridge/src/SNSAdaptor/assets/arbitrum-one-bridge.png create mode 100644 packages/plugins/CrossChainBridge/src/SNSAdaptor/assets/boba-bridge.png create mode 100644 packages/plugins/CrossChainBridge/src/SNSAdaptor/assets/cbridge.png create mode 100644 packages/plugins/CrossChainBridge/src/SNSAdaptor/assets/cross-chain.png create mode 100644 packages/plugins/CrossChainBridge/src/SNSAdaptor/assets/polygon-bridge.png create mode 100644 packages/plugins/CrossChainBridge/src/SNSAdaptor/assets/rainbow-bridge.png create mode 100644 packages/plugins/CrossChainBridge/src/SNSAdaptor/index.tsx create mode 100644 packages/plugins/CrossChainBridge/src/Worker/index.ts create mode 100644 packages/plugins/CrossChainBridge/src/base.ts create mode 100644 packages/plugins/CrossChainBridge/src/constants.tsx create mode 100644 packages/plugins/CrossChainBridge/src/env.d.ts create mode 100644 packages/plugins/CrossChainBridge/src/index.ts create mode 100644 packages/plugins/CrossChainBridge/src/locales/en-US.json create mode 100644 packages/plugins/CrossChainBridge/src/locales/index.ts create mode 100644 packages/plugins/CrossChainBridge/src/locales/ja-JP.json create mode 100644 packages/plugins/CrossChainBridge/src/locales/ko-KR.json create mode 100644 packages/plugins/CrossChainBridge/src/locales/languages.ts create mode 100644 packages/plugins/CrossChainBridge/src/locales/qya-AA.json create mode 100644 packages/plugins/CrossChainBridge/src/locales/zh-CN.json create mode 100644 packages/plugins/CrossChainBridge/src/locales/zh-TW.json create mode 100644 packages/plugins/CrossChainBridge/tsconfig.json diff --git a/.i18n-codegen.json b/.i18n-codegen.json index cb999243cc8d..ed36febbdbaf 100644 --- a/.i18n-codegen.json +++ b/.i18n-codegen.json @@ -193,6 +193,18 @@ "trans": "Translate", "sourceMap": "inline" } + }, + { + "input": "./packages/plugins/CrossChainBridge/src/locales/en-US.json", + "output": "./packages/plugins/CrossChainBridge/src/locales/i18n_generated", + "parser": "i18next", + "generator": { + "type": "i18next/react-hooks", + "hooks": "useI18N", + "namespace": "io.mask.cross-chain-bridge", + "trans": "Translate", + "sourceMap": "inline" + } } ] } diff --git a/cspell.json b/cspell.json index 3b4b510323b6..47f3a23cd22f 100644 --- a/cspell.json +++ b/cspell.json @@ -46,6 +46,8 @@ "caip", "canonify", "cashtag", + "cbridge", + "celer", "celo", "checksummed", "choudhary", diff --git a/packages/mask/.webpack/config.ts b/packages/mask/.webpack/config.ts index 8fe5fbdd2ac9..00855f7fc0bc 100644 --- a/packages/mask/.webpack/config.ts +++ b/packages/mask/.webpack/config.ts @@ -96,6 +96,7 @@ export function createConfiguration(rawFlags: BuildFlags): Configuration { '@masknet/encryption': join(__dirname, '../../encryption/src'), '@masknet/typed-message/dom$': require.resolve('../../typed-message/dom/index.ts'), '@masknet/typed-message$': require.resolve('../../typed-message/base/index.ts'), + '@masknet/plugin-cross-chain-bridge': join(__dirname, '../../plugins/CrossChainBridge/src'), // @masknet/scripts: insert-here '@uniswap/v3-sdk': require.resolve('@uniswap/v3-sdk/dist/index.js'), } diff --git a/packages/mask/package.json b/packages/mask/package.json index 37acc43db1c3..c7a6c5bd2fc8 100644 --- a/packages/mask/package.json +++ b/packages/mask/package.json @@ -19,17 +19,18 @@ "@masknet/gun-utils": "workspace:*", "@masknet/icons": "workspace:*", "@masknet/injected-script": "workspace:*", + "@masknet/plugin-cross-chain-bridge": "workspace:*", "@masknet/plugin-cyberconnect": "workspace:*", "@masknet/plugin-dao": "workspace:*", "@masknet/plugin-debugger": "workspace:*", "@masknet/plugin-example": "workspace:*", "@masknet/plugin-file-service": "workspace:*", "@masknet/plugin-flow": "workspace:*", + "@masknet/plugin-go-plus-security": "workspace:*", "@masknet/plugin-infra": "workspace:*", "@masknet/plugin-rss3": "workspace:*", "@masknet/plugin-solana": "workspace:*", "@masknet/plugin-wallet": "workspace:*", - "@masknet/plugin-go-plus-security": "workspace:*", "@masknet/public-api": "workspace:*", "@masknet/sdk": "workspace:*", "@masknet/shared": "workspace:*", diff --git a/packages/mask/src/plugin-infra/register.js b/packages/mask/src/plugin-infra/register.js index 5cbbf531805e..38c8b49ce83e 100644 --- a/packages/mask/src/plugin-infra/register.js +++ b/packages/mask/src/plugin-infra/register.js @@ -11,6 +11,7 @@ import '@masknet/plugin-dao' import '@masknet/plugin-solana' import '@masknet/plugin-cyberconnect' import '@masknet/plugin-go-plus-security' +import '@masknet/plugin-cross-chain-bridge' import '../plugins/Wallet' import '../plugins/EVM' import '../plugins/RedPacket' diff --git a/packages/plugin-infra/src/types.ts b/packages/plugin-infra/src/types.ts index e0bc35cd42ec..94a2be28412d 100644 --- a/packages/plugin-infra/src/types.ts +++ b/packages/plugin-infra/src/types.ts @@ -689,6 +689,7 @@ export enum PluginId { FileService = 'com.maskbook.fileservice', CyberConnect = 'me.cyberconnect.app', GoPlusSecurity = 'io.gopluslabs.security', + CrossChainBridge = 'io.mask.cross-chain-bridge', // @masknet/scripts: insert-here } diff --git a/packages/plugins/CrossChainBridge/README.md b/packages/plugins/CrossChainBridge/README.md new file mode 100644 index 000000000000..369c4cfa282c --- /dev/null +++ b/packages/plugins/CrossChainBridge/README.md @@ -0,0 +1,5 @@ +# Cross-chain bridge plugin + +## TODOs + +add more cross-chain bridge website diff --git a/packages/plugins/CrossChainBridge/package.json b/packages/plugins/CrossChainBridge/package.json new file mode 100644 index 000000000000..d4499c87bdbd --- /dev/null +++ b/packages/plugins/CrossChainBridge/package.json @@ -0,0 +1,12 @@ +{ + "name": "@masknet/plugin-cross-chain-bridge", + "private": true, + "main": "./dist/index.js", + "types": "./dist/index.d.ts", + "dependencies": { + "@masknet/plugin-infra": "workspace:*", + "@masknet/shared": "workspace:*", + "@masknet/shared-base": "workspace:*", + "react-use": "^17.3.2" + } +} diff --git a/packages/plugins/CrossChainBridge/src/Dashboard/index.tsx b/packages/plugins/CrossChainBridge/src/Dashboard/index.tsx new file mode 100644 index 000000000000..3052bb2f8ad3 --- /dev/null +++ b/packages/plugins/CrossChainBridge/src/Dashboard/index.tsx @@ -0,0 +1,9 @@ +import type { Plugin } from '@masknet/plugin-infra' +import { base } from '../base' + +const dashboard: Plugin.Dashboard.Definition = { + ...base, + init(signal, context) {}, +} + +export default dashboard diff --git a/packages/plugins/CrossChainBridge/src/SNSAdaptor/CrossChainBridgeDialog.tsx b/packages/plugins/CrossChainBridge/src/SNSAdaptor/CrossChainBridgeDialog.tsx new file mode 100644 index 000000000000..c7f75df14c97 --- /dev/null +++ b/packages/plugins/CrossChainBridge/src/SNSAdaptor/CrossChainBridgeDialog.tsx @@ -0,0 +1,99 @@ +import { DialogContent, Stack, Typography } from '@mui/material' +import { makeStyles, MaskDialog, useStylesExtends } from '@masknet/theme' +import { useI18N } from '../locales' +import { getCrossChainBridge } from '../constants' +import { openWindow } from '@masknet/shared-base-ui' + +const useStyles = makeStyles()((theme) => ({ + root: { + width: 600, + }, + paperRoot: { + backgroundImage: 'none', + '&>h2': { + height: 30, + border: `1px solid ${theme.palette.divider}`, + padding: theme.spacing(1.875, 2.5, 1.875, 2.5), + marginBottom: 24, + }, + }, + content: { + width: 552, + maxHeight: 510, + paddingBottom: theme.spacing(3), + }, + bridgeItem: { + display: 'flex', + padding: '12px', + ':hover': { + backgroundColor: theme.palette.background.default, + cursor: 'pointer', + }, + }, + bridgeInfo: { + marginLeft: '8px', + }, + bridgeName: { + fontSize: '24px', + fontWeight: 600, + display: 'flex', + }, + bridgeIntro: { + fontSize: '12px', + fontWeight: 400, + color: theme.palette.grey[700], + }, + officialTag: { + width: '39px', + height: '15px', + fontSize: '12px', + fontWeight: 700, + alignSelf: 'center', + borderRadius: '8px', + backgroundColor: 'rgba(28, 104, 243, 0.1)', + color: '#1c68f3', + padding: '4px 12px 6px 8px', + marginLeft: '4px', + }, +})) + +export interface CrossChainBridgeDialogProps extends withClasses { + open: boolean + onClose(): void +} + +export function CrossChainBridgeDialog(props: CrossChainBridgeDialogProps) { + const t = useI18N() + const classes = useStylesExtends(useStyles(), props) + const { open, onClose } = props + const bridges = getCrossChainBridge(t) + + return ( + + + + {bridges?.map((bridge) => ( +
openWindow(bridge?.link)}> + {bridge?.icon} +
+
+ {bridge?.name} + {bridge?.isOfficial && ( + {t.official()} + )} +
+ {bridge?.intro && ( + {bridge.intro} + )} +
+
+ ))} +
+
+
+ ) +} diff --git a/packages/plugins/CrossChainBridge/src/SNSAdaptor/MaskIcon.tsx b/packages/plugins/CrossChainBridge/src/SNSAdaptor/MaskIcon.tsx new file mode 100644 index 000000000000..f3027591ddcf --- /dev/null +++ b/packages/plugins/CrossChainBridge/src/SNSAdaptor/MaskIcon.tsx @@ -0,0 +1,50 @@ +export function ArbitrumOneBridgeIcon({ size = 36 }) { + return ( + + ) +} +export function BobaBridgeIcon({ size = 36 }) { + return ( + + ) +} +export function CBridgeIcon({ size = 36 }) { + return ( + + ) +} +export function PolygonBridgeIcon({ size = 36 }) { + return ( + + ) +} +export function RainbowBridgeIcon({ size = 36 }) { + return ( + + ) +} diff --git a/packages/plugins/CrossChainBridge/src/SNSAdaptor/assets/arbitrum-one-bridge.png b/packages/plugins/CrossChainBridge/src/SNSAdaptor/assets/arbitrum-one-bridge.png new file mode 100644 index 0000000000000000000000000000000000000000..634ec832596da2805bd31ccf9279c938e35ba434 GIT binary patch literal 1845 zcmV-52g>+~P)5ASpK>C^R7{HXtcAASgH>C@>%}Fd!&4ARs^>DK#M}HX$lDAu2T@DmEc0 zHX$lCASyN>C^jG|H6SQ8ASE>*CN>}`Hy|lDA}BT@DK#P~HXtc8A}Kc_DK#J{I3X%E zA}ci@C^R4^Hz6rDASpH=DK;P}H6STAAS*R3H%lQYHYlL*M^IrbL|-jFRpsXBu(Z2s zhMrAfbe6u{DrJ-@hQ}*qlZlU-Fg!~-NL^!nlX#f2D_)5zc(ODo-MJXoH+9SbvDR-)?n-M_F$x zYn>>W=Huk%j~l1;FiAI zZF7N+v(R;vt|KcskG0Y^qwQ_7<0*{MK~QFbq`@hT(PDg)FQM)>o#T(Z-CJ^sDSy0X zYjsp=fkl+d(c|y8(&s=>W-Ll-e4MycYJVs(LD=TlwaAP|5MzuxcefA8;r zUyxuhP>+y*kgrg0k3i3lzHrY_u+OeAFV!yd000D-Nkl)l=h3o@teyYCxnpF+wE$k2tGJS@Y6* zmgVd@LlFJ%a?=}HRV$3yC48Jpmh&vpa98E)`?Ma9T$VFJY^FrMd6aJ>_S|Zf^IAV~ z0#!L{Qo$ax%CS{4-!qPIYmAY9YzpG5y3V{|G8Hbz&4{dO;7KvL1RMxFdyH~ot2&|| z$rrigeW;Olc)l5Yq?JPZezeGB8Jvj1;hT~aqH-wG+Zo+?c_L&dAr~XUKdx#`g`%<$ zC3)2pL|7A)#^xf50l7FQ(L@A9Gy%y>(XLR#=_Nr?diE1r1lf`<5j3FvxU3y41j1p_YAlU-bM05g!C}UWMOGh z04oHSwIp}C8^W0)tLzfAf~S|~W1nUaE`Dm-Atum0c{>z@;m$J2dxmI(w@woUa0qRB zLvrkeznJ79UDTvs5eU|+g?wSM+RSFPOnLo^=$BRnE9xP4Kr^2(Nw;xn+mYz;BCHTW zzw>D9(`uQzuqfp*PBY_DwT_gb9GPZ5xUaomrdi<=XABjGHJ_>`I24L#!#Vy=(_YA!HNg8}A z+5HN-tR?JGQ$HqBy;`A?oCl<6mDj(so5tbZe2Z&-+`8BO712f&_x}THpmUgg@cTz1 zRUcJ!2m^!zK0P0K4$eMknm#|pH48Ho$X(-UWSc2scc}U@d^Px-<*rAkwfw z_L(qSe-*0VL^*Qg;DPfP+|W#oeC19>xsU3!zyeuheQK)y5Sl@m3dm)>7#iBBNo6q9 zR7_2}1MQDHo=TvFB22*-&d8>>o#rUq6vEn-P;%7CUOvdRUL7O*UjRAzP4 j?L1~KcSlF&&N$1zyw+kM=y#N!00000NkvXXu0mjfWJ*RY literal 0 HcmV?d00001 diff --git a/packages/plugins/CrossChainBridge/src/SNSAdaptor/assets/boba-bridge.png b/packages/plugins/CrossChainBridge/src/SNSAdaptor/assets/boba-bridge.png new file mode 100644 index 0000000000000000000000000000000000000000..b41c5c9b9b2c2398e16148e671e937d0b8f2367a GIT binary patch literal 3054 zcmVhzED+{(p6Pg5(kW z-Z1m(oF6jMHTmaubys!Wp%OM1rVTTena>+d-@-< zI*cz9z!WfePRHD#h1mK-dj3k}Rm$}K{aTpAQ`Yj0dP9`gq4{2;8pVYatE8(*cLa=ne@iapD zswOGW4d#6$FtVJGm@oAhkZA~nY6AG{ciJ~8t zeQDAHqsN#XlmEPq8hR6gge~&1 z6^XJRRva)Jfv!KU@aC_DBWE{4APBi~4Ni$kI2cc`vN9Wy{2x&b)T9!qQjI?@6Hd#y z$iX`NewE-}-fRTQVjQR#8?2?H?LQe;vI6Wxh;&4&4rZ0q_N8L%7cHGkT1kkN9aNx> zlnv2$j9CfvTX8AHEiIk&R4Z8>6{urnTlg+8yV6LV2eNf7snyt+(dWqxDkocY#Ows} zrTZ*EYX?@=guiZBAX_d$x}02?lbIC(j52%XydF*hP7^ZZbQWnjf`m03oXtw00>+u4 z)_OVF@e3hEj!Y{`GT@Z zVniDxh`vY`LzI~DqBA070|ZK297`kkEhIR(mbgF>q<1IAfjB~%{17=<%Q=|=t=bdz z{6z?oWm$;9YK6;}+mR=?;I!~Zx|qOXPDPentfpqJT#r+78X`qA1Y{C?|5KugZx%yW z^mMX5fRK!#s)!#foG@<}AxxHMQFgEh3lJweAzW6)ua_-wG?nm4IN{4!zVgnHdVQp9 zf>hyy0&GX7oQqIV5eK45>^SK<>Fs2~azdW z9u?H|yITz?RmNCXdVeP2i)dm|DL~6Q?iuHn#+>B)yxS>NO(-Njv1p^+=KL zVNC#`+la>qQm-x?#*IPg*V{jEq;w>S5F=Y74;v6G-olYcU1QQ!hO+e%$IFZ0GoSGL z6$3J*KQiProXmQRIJIk|R(uqCrX`_KVl>M3?S23ADqZDYJ>n5I$ca=;s1?bL2y%JYEGbT8^yBrguq*bKd&3(O_Cgld~89e^hE1U1e<0} zQ9d#lRpKMzzHcWCHa6;grM$gSB|H!#GEz}5A&LbXTI~4!J|KihPnG9IipKDntA{{J z8(P3XV^mO$5OvkT;nJ@Nak4| zIMLC#S-kHc(O_+TPgpN6xUO0bw~zP2ZpgrUE7$*xMi&m;Uz|UOp&Xl>XH31D>-~6! zkRw+hPQJsNQccA<&)Dlya;;pu@HdN{2$R*(t~DnzYn9tS>y!OH5JxR-(WFG9R{#~;@kOK<@ zQt3sM@W${d_x(^6%A;Cb1hyA&8I36y5yY{_^WO8Gp0I7%LJ3*8v~$YwI_%#YuBKX% zoq9#%Vvr-(AV$1`k=pe`{!GPKUj|z7O%@?T&O)*nicMb^ea>z3I@D#6YQ%=ab@hrz zj^p4vPHh-DHo@!npJ7?f>+W;juM>i#0}8MkA;J@Fx@z|M2T?KRpkeV$l`-PvTga1} z@aGK!YSb;d;j?}9Wt3v>-~3s)y6|)>TVx#1V+XJ(FB>28hO%{XT#?P=qCLh#fo!=F zf3XjZ%Cn~*)dDj|D}i3>KnRg;$dzjmEn32F{-a;-G<6ax1pfuk-+zSN-~snmws~{# z3JWtVBL&rC!qomr?SZNhe!FC;_F74D2)2Hwd;5zrS1rpQhvNuoVytR|`TeR58a6Bb zbru|3D#wIlU4Aa+=Vig`*B|c%bz2*h9oQdEvuB`i*;mZnMl5{myM2)DI%)Ema~V5& zglT$C)@=|WPrtCBfbg(Qw~ zp9QNbq!yof){{1ICTNv%tUXSMm2aXz9UivA?q5}_@PjK~|2}a4?gZSA9zf|gUVpgg z!w7*l9aIl?78WAtmH|z?H4!I;v8E@q&RX3l=jlZ_nMvw5%`JI|6b zExS%$!Q$K~i*(_qt{yITV4S~ZH{P|Ur?fo`w4h~M!jTkJ6H-@Fyy%HPu9Sk`B0`ON zk3U=M(39|4I3Y|{L#F%>vg9Hbrvm)9Xcm~)KI<))F`Ct;o0BTC$EdUVZOD=f5h0qY z78!0l$LP6)H+r*}uM=K*htPWzsUxC*3}P|dS=?c2%aA4}sQB}*C7RWuqZlW8Mr*3! z-GwSi-SmxWtWvci z7&8(lnrT8MY>v!2Mw+lNmzdp*CA~mv&!n1Qtchnjo6^_g%wqCQK$vUHhw3w#pxM8m zFIbXHCgX2T-$XTt`GvWqpD2o7nZAsJIe*F9Nakziyas~gGbb2dHTM6QIWTP)KV}(o wkO^Y4{;QevTH#~i%mHRTGq&)(E>wc{|KhvNTx5%K2mk;807*qoM6N<$f@O88+yDRo literal 0 HcmV?d00001 diff --git a/packages/plugins/CrossChainBridge/src/SNSAdaptor/assets/cbridge.png b/packages/plugins/CrossChainBridge/src/SNSAdaptor/assets/cbridge.png new file mode 100644 index 0000000000000000000000000000000000000000..e9ced6d2c547bf6433227b7d9d2de9c7319042cb GIT binary patch literal 3949 zcmV-z50dbSP)M5luT)vx1i#g@8N;`@m>3su;g3IBeQkxbo{{-fgvTsVM zl%w!TFNaEw$Qh>h}jU8jWc_pA)zb{5GA=Xfl})#$rybRzD+_6+ZaX#UPAQ z=5yOqwD}igI2_V)xui#dH6Se3#M;{-iM`=fQS+dq!qgiLSe`}k1qct%IwF)2&)~xg zAaUYQ+rl6$f(G`)-rGWzl}bB`M|k%{c#YIL%LjrLamcWN@H4iy5lY)E&gv-c;a!su z=j=7e1HE34A_kmkFYHt*kQ{`N;#>nuq1r?hI2(Ht&Rmi*<0x+7O@mjZo4|Iv%?UWt zSS*&*>2x>VB=v`*xRzHBL}lPj{D+j^ki%V`TE*Zw{>2GaBzV%3JV<7aijx45&;~qI z=8^f4-1fyuib%NIrRsLJJLXc3B$qU_+8yE+0C&B)4?+{jr92YV%0qR--ME=_6vue< z$C5Ohceu|{sRxZi>M`NVS8r;+)g-XE{#;3e7B zMe+VK#?!Xl{e7{$6x(*P7~5@I<*^m3jk1lgjh%g8r^c=~d28)*oqG3o_c`yPoS$IF zrqW()v$Vmf zOoy{C37#cs@aWj!#guM70!!l&Sk8Ox90ZpW)Vc)T6V57vSsV}F!gzR8^Qi;su_C^O(xrNK=XcyuZ7Xp-R7CBV0UQqO~b z2|=w&L~v~~0?Pxo8NKvB*CdjgRLzYw*D*x*1ygUI3T-=#5ClLsYY~x zolBVVTtfGR;9PJAEWNp~tEs*W*n85BLvksS;9ig{oIy~DlB2u}5(y+8UNt3Lwt_IV z$y6$w{mFD;8XW!UaA<+=E zyc4FLLYO+TVeQGGvf$9q0uh)bTrg zgrv=aozAf-7_UDMRwd(i<-@MKkC67rGI)%Ri=t_EN_ugpAod?Qv=@#gkHFYlN9F+(Wik$d zEAn9OruvFtXe+>ET`pWJUd2%vh67}9N}8RLUiqcn7kVj8NoBLkMsOqg0T zVd=|puH?HC#RW!BLphuIag#%fr+O75l{v1i!s$e zNNw!pRyL@+0OsC&n3-}Gk#c=Gu(Z(?QCEo?rT!O455XzLV}j|;z9AdN)*Kj{m?{JLQUUj@ya$`cKgBjvFZKl1QyZ||szBtg59y#A zVN(|oY7T2n9sw6ZU!To5xf1xP))Kn3lATeG(V9|>HD85^);n-;R|K&f(Mjy4O`G!L zM6StEf6VHaF;aI8Px4xf)>UGxzFa!-$<{JV)aDaX3G^*&U}G-Rj)hfq8@AgQGc6CD zyEhN-!!~mt91D3h94Ljcjp@p?ovh1aJjSgr#zZ6CQ&%o^%y3l&hItOom0!wMhvEXE zP_=l%OWfrLbPZv!`Z^5$a21BDufk}<)fj8KY8p~YC8pZg%XNjAtS`V6Yg6FY_nFRz zFFO9=y_?|s=^acp@%t?T3e~{c)Am1%H87n!uE)?frTFW!Vhr;v%nj(x=71KG4UsHjh@5;n)63n&u>+7rVch!wBDBg)_^Ksfip~WJ_#>JDvhYw#? zu$})9YYj}3BvJ4$U1+^y_4Ih=tT4{}Y}?;4aJDga_h@a~ww0G%x3>31wDGd@<*Vw# z)}>H73{cx=W6p$xIU{D0WI$zb78Z~s%3h@0LKfaTDxW=QElDMHi1KFs*mR-Pd6NeE zn@#oVQSR3f#|$WKv!HfcaD4CP`yNlb)CD5iUk}nTw(N&`s67q>GNU+PMX^VR%BY2a z34D;i`=(JvGqLWk4{_n#8PFb(q;pvI<%>+E8GQc?%$qQA--ODr3B^7Js#A~BpoHR} z3u|NJ4}~Cb!Ts2Y1KXi=yQv@>3F6XYL9y42(tsIi+ccE=StgA!^#=7geRwAxmL1!@ z0t-GP2^~{~YRUr!`ZWsQ=G{zM9{W5{~+5gBin3&(j_6+ zY!DNf`@IJvy=2;U=WN@J9Jd94TT;n^6h41n~cb|+L39Muxn}l z$q_X7<9A4q7nx=Ua_tTXl3GndO@%&^({E+L?Pqm;5)a!>AKAlq%S64hLOok1f>xgMPoCmi*k$n-HrF5`-J!_w0yOITC=~6^!L=%IDY&D z{tm~{**k>atDiyiLoXs#J_7M0{H`7G8aILY2-uAj0q+!DNVtxPa|IE zMfiOOh=~e+hQ}dfdSAzyHEY-)-z$EI@1?16SB=%B%U7VGwF^eck69KM?2;S*R{4c< zE>w~C(n6B7=mqe1jTf@-8Pqj*V$It1c-VG`cvr4m2_+Fmio_&HOsrNT$3+}IVt9_q zb|P9soGq_H&1a#iDoUji_#A_M{LbU{qOrPd+f%m~C=_YeH82XD%_E4pw1hk!BpRMY zyf#RJo(4gQh(-UGG?nGXw;zNq-*0gEF!u51%S{H9!TuD{1Oslw<+u-~Y z18R%HX$O;bWas8UJpg3uc1yqv&=JLh3>R*cvV7G#lN_LBwQ{&JxJpnE3`6$=`oLHEMN+Qs(l;_nV^US-w=o{fXL^SjB&CP@7VWyALEh1$?;r|WE?l^P26+cYHETr! za1XkhVfhth|G^{P$;n^5Je@jwjzSjr3h(4#G{lrak6t>x$~^#jG?Vb_{6)*XlCysE zHj1{eonFa#_UzgJv*(8pOh7>Zwti?8p&UDLhHBJr78N;l8nvV|=Pvl$Wbo=0ojrRt z8gkHGp`76Mm#0q$F(Lvy2n-d;w%Jd#cHNS8=sZ>b|$NCm*6o(9d8kdt7 zBJq%Q1l<4cm})msEJ*@a*{p{_R9phf@QDlz8DUt_SBrp`E6M00000NkvXX Hu0mjfc#ECR literal 0 HcmV?d00001 diff --git a/packages/plugins/CrossChainBridge/src/SNSAdaptor/assets/cross-chain.png b/packages/plugins/CrossChainBridge/src/SNSAdaptor/assets/cross-chain.png new file mode 100644 index 0000000000000000000000000000000000000000..892dd5876ecbc92001d66663ebb093d0e50fcc89 GIT binary patch literal 3527 zcmV;&4LI_NP)HF8z$V;sGG@s_v ze40=5X+F)T`81y$KdqgqT`fJSj-x%P)Y0xFU~VWLrP!0?Tx<9oBf@K;sAmw~qqwuY z=A-+K+hb=o&i3XuYTLWDw)UrXMQRQS;*b;#X<<^pd2hj9c^js_irk z!-naan$*g<^cZKZYBlz;PDN@`Yfq{bF9HY;l|0ED>q{G{eR$7yn9v^9*bbdz4e{^e z>$yF0M)y!2KGzYMLC5%lh{k{6Fp7fKM6c!=<%~P$*ScSONsu#6&#i?toEGodiq`NM zcc(x*6`4WD`_qOl|KCZ=3-+g}Hrli6suPY#SYOv%?rNvM1>4;BVLgB~u5-Vi>WrZt){OR5L-zAI?K4`_8rN>W_A}DwmzAEbyZcFx_cZETJvtwq zL3m*r1Z{)#(irigZ3Ah9`U2*(rnz6co}6|21%F=(RG)H;uBT@EXYE~VEk=509kNb3 zc0D?SPVhw>C(x)98VTxg9F+Lkl@vVoQ4;PsxCZyUoismxcMV={lS}D2aGDNZYqK@K zzcEiY>~GZ1Xmn>HGw9^Cj5)~{OatZ;5sA2VO*rsX8ovA7D#Y$zf%ttZ6eZVq$78GT z#6ObujF=^c$qWV7fjCT+eY%I(j$%y!Nz~^Q;q@LI1v%0mUFRz}Awd z;pZPFA^z~{|HOBmS%dd4r}?bDu&1A;%R7CJWSHFp(j#NCP^{FMbC{oWYbMb2wFohf zXGUpI8ooqPW+;opC}xb*8MycT6vQ4`gLsG-5zduw{ca78_GZngp{zko(h^-oXSkgA zVXj7<8_TgV`dE|nj%0@BY>YgZ(6p(T2tIU z?0?cDngM6oBw+^+n{;_H52BZ|npo5OL}ySt86+n0pE)pc{r$r^h`*kL7!qf;sb8ar zV01k+2zm9g=*k?_)|}Ysvy!cCdiRbf4Z>fkrh^A$A;{0+fFB;g7kxXg;0qH6v3D?! zIrSuJ-_;K89qJ}+(G9WVPf+KLJn7KAHM%)b8U#M)$MR$l{P-lkRn$fL9K2=<`}p-RUlo~7jzCA zm5Z$oT zhHBI|r0>l%x`s%vYr1F}&8b6IqTsYt+v>}`Nk2M+NbJ&N!Cb;&2%3`%YBG~V4_1k_+HoFO@xqfu&^L)bp<@18C|skYIaGMd$$DCl0d-{q>u zb%X}duS$Z1Ip;_e2=hQ^5#lE*5N|_65Y9Emycnat#&3UFg3m{t2I^^ahG36tg=)*y zsiMi3>l@7JohceVXU~cbN68&g8uT?@uJcC0d`;jWsxe2TNA&|;C5WG{SYi~<5LL<% z?PKo;7s_Z3o~M^pJx88VU0K&X+NWGiDgc>OuAw>8Me6zI@Xke}wWlHX#`Wk7>O`?C z_!C2uU~|NuA?d8{oRS8cMmai3r#Ut z^5_i0k275k5RP2q0GneJiX2;^$_wz1sKJ!+VXbmBuwjbnRX*xAze9bY12k zkr~vL;2{csq>a{`cTd|jj#!&uA0fR^Ot|RuovzpOG?~y3p@3^8r{(smM&r4lj?AE* zX&NqYK25Pi(bD63x<^TH-*h+h7$ddQ&=}fZke-+hBWH(U^2kM)Idq&EYwLl5z6I!Z zdj9N?PRS6Y7pXx+FELXx`0Er9gE^r+MfVNNN?*@X9z-KrdQNqMJ)*(--1A9%+zz>) zJqv|SbqKx6n^?F(_z0hs*&oCwPiz(zUs=(fxY9F$QaWHW%HY!P}62{0+$8_afx) z7Yg^kB)N;q9-Gg8&~CLAYfdmXGJ^(gmU$3GMRNLEHT8KQ|LdNbJ=C4@BE=;+3KG7Rgg2A~m3}O_@hM-&_6E-#H`eKFl z0&4IliM1F{5BpYEb0X1p4e}4a0XZc9@Bt=A@fUAm)Ee`=p!r)&4q5qA3+pI$20}49 zgYd;bp&=ao-WZy&g*mcU&kW61Y>vRtyp5tOsBQ^XUOo=FUmgna4#zx3tu^;~7xKRn zCN9s)JZrq(Wv&vPLHGhNG$&9#j4vAGV@r+Ztk(hNl2!W0bY^N9b3uD{O*K_dbJ8d6 z+^;`G4nyvd!;pWJ@-QDse3W8{M?Yp3KDY|@{$jkne`E#?iz)aWQvu8=8j9n$DnRD! z|ic$`0Gj(+da=VX1mU!|DVYkE_)24MBlMDFm2}1f9S6;s?nrh4_Y6tg^%pm%r zr7vNOGyte3CT~}vy1p}mMi)hobcHgX2AgCy`R|r>SW2&(#Z=A4AYV#LK9{UD=;17$Gd^8_%pbmn>@ydX zi;#U5*^mcZ!aB@lj!Q>w7++grm1ATEjW1O}OcKU9I;NHzOro0mR(48`+OH(i1X> z4NGip689%`kDhfkp}Lc*DM)X+FNL3?AtsA7Cd7u@`Lp6JHbR~5Pi>VKn>HH4Zt4vXI84L&%59jjP<)FmChgMUBiMQacs{2gQSRf=0PgXZ8K-LHrNTZ3n|UDx^ZBUQ6_ zu?n|3koGDpbX8$yaqD}8dkKlr8AN6<`l$#|698kdE`2f3omrE8Zq4b0a;}*bMRSL* zqjzw7T~uw|@8$**5Vhd@gCLYn)=#fWCq5h ztOq?0L+gGW+84w~4N4(E%%|#RK3T_0a&05_urIZ&OHZTj5z|6vH)qYy!?kGXT%BX@ zz_|Uc4&6ICgXUA~9rW^>v4Dml4ZZF11-z)&lRn3Fv#|L&joaKok=o_qDDbS7$P8La zm3HBP)FNJVF-^nQZKU2(+8BxfvTkr)YJa~_chRkjh8j*ag0;m2n!2vJt~uO1?=1DS zPpmDaU{^%;IFoLrP3sa4M!>&3*9xsOlxK`VBzNoKTK8z5jav8DUEVmSF2)H=7L7$fk)$lN9BV@=7C7#gGT3oM&g1;<$_1%fk)+oN9BP><$*@! zf=1vFl3wVsjPALZ@Tr0AkzVMjfbF@L@W7+;v5fEE z(fG)&^TDI?;L-S+YU-J4>bRHi*v0p-jPB^%`}gzx$*%P0-TI1B=g6<~=iK_(#`nms z^d5in7XSbNC3I3wQvlx(AV6@x?~wj)fPYZG-tO-(fRB%GZ(v_vV7||bL8@4CkK=6Z1?uij-CqCylXj078!J*GDaG@ampQlq zh}Z@VeAW+MGlu_QZ~UO|LKk@7@1czU%xP^wLUOgx411`74V|tURRv~Th88f_lxmKa z%sFUq7+S*|O{^Za;A{j9JjRwhf?9^ynxVO#?lq0D6Rt9^9(LkPnjL4@5mw!&Id*2Q zX;Akz)dgE+``j{|ZiCXBBuSz@+Hl_d!t!s4;QQKUa=fXaWt<%OxwbEfNvVF3hVogI z^rWI${}zIHmoB4wl`)@JihLw+bD!!eN5mpa1Y6YOm#wb2MG=>`C@93=U(oDig!68 z=7&|tYPTu?-z54`-hk^kIdY9E@8D&#h)5&Tt6{)2Q=^ko5--z3zE5jKB$<`csX4pK ztJz2Nx3`(UWu5ILG(p5VI`fED3y0TF^F!Xeee=+sJRUrnZn#sJ{ih?1@J|6CG11ptl)V(Hb?y)_3cvTgrA zjq964u#l6Pv(c(&pRZzCcPSYd=0>YdL<{+$3C>XqtvcO;Dgyw^lISYXg(H{)wk1(M zx^Tpx^{4DbwnUW)5bmiy9z%egxj4~RhzUQ=;P<-=;-R^=ji3<=jZ3?=I7|-F4L_<>lw&gwg@=;r9@ z=H}?;=;`F-=H%+?=I7}D|Nj600RH~|>FVqJ{QUIv_3P{G=;`YB_xSJd@cH@q^7HiU z?e6dJ@%{b&`1$!DARs_MK==3e@9*#E=;`+M_VMxZ?CtFk5D@zM`(R*T-{0R~Utjh1 z_WS(&^Yioa^Yd_UaG;=|fPjE7FfdS1Q2zbz`}_O<*sQ<5zmSlSAt539`};7?@6XTA z|Kh;u>gxa9w*S@EA;`B+Pfq~Ai~r!^@bK_S(((Vrf)}w}^%Tmo!1Vk7?A0L1 znzZrz^6rBu|LV5@001a-QchC<-w?kb?{GkG{(yhpknUfAK#*WikI#>fzEE&5Fi^0s zFwf7gu8%PE^J$X+00Ub|L_t(|UZvQDcH=l0hGEH22fJ+tcb55++2NGA!;H(!%yjWv zM?NE0b`{I}UchsH$rObsGM;aAU#1iQ=&NS8u}tb@G)xa;FW5WmQ{VyL2Az=t!kAUE+?e zS1pax>$Z%D)q`BIPd;8D3+UB_cJ}j|w1SWWx3a23?hSDRbcu;R zhyKmFRT&c7l;9N9~xKS=;BLSt*SMT%w zX1Vqc%Al(nkf5d|yR@zWi4IP?D*?XQN=Pm3$yZIJg4PRrzLP?`c#XV{H4TW}b>$u% zLlc1B|dhUdVkM@BG61hAG;SpqsOgq(clF zo)+|8@f9!zX0O^qE$FHQO&LpI62dpB2>tXm?`IjhH_dnd{wL`cr3VxP8=exHUkrAXHr5AV$X`ii{P& zUz^8FA~Y`;M4dx{;Y7&{fsRAw*Gj2FR-P9QfyI_Vs$`{9JW9NRayW|7lo)kqOaO>R z;pD+lN*o;};m8M?&1V}1(aM@xq7+%=ihfR`Yo4b7(CNJKX5%fD@*kd8A2wnnQuF`- N002ovPDHLkV1oXE@h1QP literal 0 HcmV?d00001 diff --git a/packages/plugins/CrossChainBridge/src/SNSAdaptor/index.tsx b/packages/plugins/CrossChainBridge/src/SNSAdaptor/index.tsx new file mode 100644 index 000000000000..61748810c41e --- /dev/null +++ b/packages/plugins/CrossChainBridge/src/SNSAdaptor/index.tsx @@ -0,0 +1,31 @@ +import type { Plugin } from '@masknet/plugin-infra' +import { ApplicationEntry } from '@masknet/shared' +import { base } from '../base' +import { useState } from 'react' +import { CrossChainBridgeDialog } from './CrossChainBridgeDialog' + +const sns: Plugin.SNSAdaptor.Definition = { + ...base, + init(signal, context) {}, + ApplicationEntries: [ + { + RenderEntryComponent({ disabled }) { + const [open, setOpen] = useState(false) + return ( + <> + setOpen(true)} + /> + setOpen(false)} /> + + ) + }, + defaultSortingPriority: 2, + }, + ], +} + +export default sns diff --git a/packages/plugins/CrossChainBridge/src/Worker/index.ts b/packages/plugins/CrossChainBridge/src/Worker/index.ts new file mode 100644 index 000000000000..6c436f1cb4fb --- /dev/null +++ b/packages/plugins/CrossChainBridge/src/Worker/index.ts @@ -0,0 +1,9 @@ +import type { Plugin } from '@masknet/plugin-infra' +import { base } from '../base' + +const worker: Plugin.Worker.Definition = { + ...base, + init(signal, context) {}, +} + +export default worker diff --git a/packages/plugins/CrossChainBridge/src/base.ts b/packages/plugins/CrossChainBridge/src/base.ts new file mode 100644 index 000000000000..b88adee59a7f --- /dev/null +++ b/packages/plugins/CrossChainBridge/src/base.ts @@ -0,0 +1,18 @@ +import type { Plugin } from '@masknet/plugin-infra' +import { PLUGIN_DESCRIPTION, PLUGIN_ID, PLUGIN_NAME } from './constants' +import { languages } from './locales/languages' + +export const base: Plugin.Shared.Definition = { + ID: PLUGIN_ID, + icon: '\u{1F9EA}', + name: { fallback: PLUGIN_NAME }, + description: { fallback: PLUGIN_DESCRIPTION }, + publisher: { name: { fallback: '' }, link: '' }, + enableRequirement: { + architecture: { app: false, web: true }, + networks: { type: 'opt-out', networks: {} }, + target: 'beta', + }, + experimentalMark: true, + i18n: languages, +} diff --git a/packages/plugins/CrossChainBridge/src/constants.tsx b/packages/plugins/CrossChainBridge/src/constants.tsx new file mode 100644 index 000000000000..03d5249b97f2 --- /dev/null +++ b/packages/plugins/CrossChainBridge/src/constants.tsx @@ -0,0 +1,53 @@ +import { PluginId } from '@masknet/plugin-infra' +import { + CBridgeIcon, + ArbitrumOneBridgeIcon, + BobaBridgeIcon, + PolygonBridgeIcon, + RainbowBridgeIcon, +} from './SNSAdaptor/MaskIcon' + +export const PLUGIN_ID = PluginId.CrossChainBridge +export const PLUGIN_DESCRIPTION = 'A cross-chain-bridge plugin' +export const PLUGIN_NAME = 'CrossChainBridge' +export function getCrossChainBridge(t: Record string>) { + return [ + { + name: 'CBridge', + ID: `${PLUGIN_ID}_cBridge`, + intro: t.cbridge_intro(), + icon: , + isOfficial: false, + link: 'https://cbridge.celer.network/#/transfer', + }, + { + name: 'Arbitrum One Bridge', + ID: `${PLUGIN_ID}_arbitrum_one_bridge`, + isOfficial: true, + icon: , + link: 'https://bridge.arbitrum.io/', + }, + { + name: 'BOBA Bridge', + ID: `${PLUGIN_ID}_boba_bridge`, + isOfficial: true, + icon: , + link: 'https://gateway.boba.network/', + }, + { + name: 'Polygon Bridge', + ID: `${PLUGIN_ID}_polygon_bridge`, + isOfficial: true, + icon: , + link: 'https://wallet.polygon.technology/bridge/', + }, + { + name: 'Rainbow Bridge', + ID: `${PLUGIN_ID}_rainbow_bridge`, + isOfficial: true, + intro: t.rainbow_bridge_intro(), + icon: , + link: 'https://rainbowbridge.app/transfer', + }, + ] +} diff --git a/packages/plugins/CrossChainBridge/src/env.d.ts b/packages/plugins/CrossChainBridge/src/env.d.ts new file mode 100644 index 000000000000..868322d5ff30 --- /dev/null +++ b/packages/plugins/CrossChainBridge/src/env.d.ts @@ -0,0 +1 @@ +/// diff --git a/packages/plugins/CrossChainBridge/src/index.ts b/packages/plugins/CrossChainBridge/src/index.ts new file mode 100644 index 000000000000..ec9b1a34e7af --- /dev/null +++ b/packages/plugins/CrossChainBridge/src/index.ts @@ -0,0 +1,23 @@ +import { registerPlugin } from '@masknet/plugin-infra' +import { base } from './base' + +export * from './constants' + +registerPlugin({ + ...base, + SNSAdaptor: { + load: () => import('./SNSAdaptor'), + hotModuleReload: (hot) => + import.meta.webpackHot && import.meta.webpackHot.accept('./SNSAdaptor', () => hot(import('./SNSAdaptor'))), + }, + Dashboard: { + load: () => import('./Dashboard'), + hotModuleReload: (hot) => + import.meta.webpackHot && import.meta.webpackHot.accept('./Dashboard', () => hot(import('./Dashboard'))), + }, + Worker: { + load: () => import('./Worker'), + hotModuleReload: (hot) => + import.meta.webpackHot && import.meta.webpackHot.accept('./Worker', () => hot(import('./Worker'))), + }, +}) diff --git a/packages/plugins/CrossChainBridge/src/locales/en-US.json b/packages/plugins/CrossChainBridge/src/locales/en-US.json new file mode 100644 index 000000000000..37075139d2a9 --- /dev/null +++ b/packages/plugins/CrossChainBridge/src/locales/en-US.json @@ -0,0 +1,6 @@ +{ + "dialog_title": "Cross-chain", + "official": "Official", + "cbridge_intro": "Powered by Celer Network. Support $Mask!", + "rainbow_bridge_intro": "Bridge between or send within Ethereum, NEAR and Aurora! " +} diff --git a/packages/plugins/CrossChainBridge/src/locales/index.ts b/packages/plugins/CrossChainBridge/src/locales/index.ts new file mode 100644 index 000000000000..d6ead60252e4 --- /dev/null +++ b/packages/plugins/CrossChainBridge/src/locales/index.ts @@ -0,0 +1,6 @@ +// 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 + +export * from './i18n_generated' diff --git a/packages/plugins/CrossChainBridge/src/locales/ja-JP.json b/packages/plugins/CrossChainBridge/src/locales/ja-JP.json new file mode 100644 index 000000000000..0967ef424bce --- /dev/null +++ b/packages/plugins/CrossChainBridge/src/locales/ja-JP.json @@ -0,0 +1 @@ +{} diff --git a/packages/plugins/CrossChainBridge/src/locales/ko-KR.json b/packages/plugins/CrossChainBridge/src/locales/ko-KR.json new file mode 100644 index 000000000000..0967ef424bce --- /dev/null +++ b/packages/plugins/CrossChainBridge/src/locales/ko-KR.json @@ -0,0 +1 @@ +{} diff --git a/packages/plugins/CrossChainBridge/src/locales/languages.ts b/packages/plugins/CrossChainBridge/src/locales/languages.ts new file mode 100644 index 000000000000..cff1155ab4cb --- /dev/null +++ b/packages/plugins/CrossChainBridge/src/locales/languages.ts @@ -0,0 +1,36 @@ +// 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 ja_JP from './ja-JP.json' +import ko_KR from './ko-KR.json' +import qya_AA from './qya-AA.json' +import zh_CN from './zh-CN.json' +import zh_TW from './zh-TW.json' +export const languages = { + en: en_US, + ja: ja_JP, + ko: ko_KR, + qy: qya_AA, + 'zh-CN': zh_CN, + zh: zh_TW, +} +import { createI18NBundle } from '@masknet/shared-base' +export const add__template__I18N = createI18NBundle('__template__', languages) +// @ts-ignore +if (import.meta.webpackHot) { + // @ts-ignore + import.meta.webpackHot.accept( + ['./en-US.json', './ja-JP.json', './ko-KR.json', './qya-AA.json', './zh-CN.json', './zh-TW.json'], + () => + globalThis.dispatchEvent?.( + new CustomEvent('MASK_I18N_HMR', { + detail: [ + '__template__', + { en: en_US, ja: ja_JP, ko: ko_KR, qy: qya_AA, 'zh-CN': zh_CN, zh: zh_TW }, + ], + }), + ), + ) +} diff --git a/packages/plugins/CrossChainBridge/src/locales/qya-AA.json b/packages/plugins/CrossChainBridge/src/locales/qya-AA.json new file mode 100644 index 000000000000..439535f8dd96 --- /dev/null +++ b/packages/plugins/CrossChainBridge/src/locales/qya-AA.json @@ -0,0 +1,4 @@ +{ + "name": "crwdns13280:0crwdne13280:0", + "__entry__": "crwdns13282:0crwdne13282:0" +} diff --git a/packages/plugins/CrossChainBridge/src/locales/zh-CN.json b/packages/plugins/CrossChainBridge/src/locales/zh-CN.json new file mode 100644 index 000000000000..0967ef424bce --- /dev/null +++ b/packages/plugins/CrossChainBridge/src/locales/zh-CN.json @@ -0,0 +1 @@ +{} diff --git a/packages/plugins/CrossChainBridge/src/locales/zh-TW.json b/packages/plugins/CrossChainBridge/src/locales/zh-TW.json new file mode 100644 index 000000000000..0967ef424bce --- /dev/null +++ b/packages/plugins/CrossChainBridge/src/locales/zh-TW.json @@ -0,0 +1 @@ +{} diff --git a/packages/plugins/CrossChainBridge/tsconfig.json b/packages/plugins/CrossChainBridge/tsconfig.json new file mode 100644 index 000000000000..c8c34c61f89b --- /dev/null +++ b/packages/plugins/CrossChainBridge/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "../tsconfig.json", + "compilerOptions": { + "rootDir": "src", + "outDir": "dist", + "tsBuildInfoFile": "dist/.tsbuildinfo" + }, + "include": ["src", "src/**/*.json"], + "references": [{ "path": "../../plugin-infra" }, { "path": "../../shared" }] +} diff --git a/packages/plugins/tsconfig.json b/packages/plugins/tsconfig.json index 855d124c6fa3..56c3716dd4f8 100644 --- a/packages/plugins/tsconfig.json +++ b/packages/plugins/tsconfig.json @@ -9,6 +9,7 @@ { "path": "./FileService/" }, { "path": "./RSS3/" }, { "path": "./DAO/" }, - { "path": "./CyberConnect/" } + { "path": "./CyberConnect/" }, + { "path": "./CrossChainBridge/" } ] } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 729a54eba920..a1e1059cffde 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -309,6 +309,7 @@ importers: '@masknet/gun-utils': workspace:* '@masknet/icons': workspace:* '@masknet/injected-script': workspace:* + '@masknet/plugin-cross-chain-bridge': workspace:* '@masknet/plugin-cyberconnect': workspace:* '@masknet/plugin-dao': workspace:* '@masknet/plugin-debugger': workspace:* @@ -448,6 +449,7 @@ importers: '@masknet/gun-utils': link:../gun-utils '@masknet/icons': link:../icons '@masknet/injected-script': link:../injected-script + '@masknet/plugin-cross-chain-bridge': link:../plugins/CrossChainBridge '@masknet/plugin-cyberconnect': link:../plugins/CyberConnect '@masknet/plugin-dao': link:../plugins/DAO '@masknet/plugin-debugger': link:../plugins/Debugger @@ -622,6 +624,18 @@ importers: devDependencies: react-i18next: 11.16.1_d4f4881e55b5d63494adb9d00faf9797 + packages/plugins/CrossChainBridge: + specifiers: + '@masknet/plugin-infra': workspace:* + '@masknet/shared': workspace:* + '@masknet/shared-base': workspace:* + react-use: ^17.3.2 + dependencies: + '@masknet/plugin-infra': link:../../plugin-infra + '@masknet/shared': link:../../shared + '@masknet/shared-base': link:../../shared-base + react-use: 17.3.2_react-dom@18.0.0+react@18.0.0 + packages/plugins/CyberConnect: specifiers: '@cyberlab/cyberconnect': ^4.2.2 @@ -17409,7 +17423,7 @@ packages: engines: {node: '>=0.4.7'} hasBin: true dependencies: - minimist: 1.2.5 + minimist: 1.2.6 neo-async: 2.6.2 source-map: 0.6.1 wordwrap: 1.0.0 @@ -21026,7 +21040,7 @@ packages: react-dom: '*' dependencies: css-tree: 1.1.3 - csstype: 3.0.10 + csstype: 3.0.11 fastest-stable-stringify: 2.0.2 inline-style-prefixer: 6.0.1 react: 18.0.0-rc.3 @@ -23732,7 +23746,7 @@ packages: /rtl-css-js/1.15.0: resolution: {integrity: sha512-99Cu4wNNIhrI10xxUaABHsdDqzalrSRTie4GeCmbGVuehm4oj+fIy8fTzB+16pmKe8Bv9rl+hxIBez6KxExTew==} dependencies: - '@babel/runtime': 7.17.2 + '@babel/runtime': 7.17.8 dev: false /run-parallel/1.2.0: diff --git a/tsconfig.json b/tsconfig.json index 79afc1ef69a4..712d80c6714b 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -100,6 +100,7 @@ "@masknet/plugin-template": ["./packages/plugins/template/src"], "@masknet/plugin-cyberconnect": ["./packages/plugins/CyberConnect/src"], "@masknet/plugin-go-plus-security": ["./packages/plugins/GoPlusSecurity/src"], + "@masknet/plugin-cross-chain-bridge": ["./packages/plugins/CrossChainBridge/src"], // @masknet/scripts: insert-here 3 "@masknet/plugin-wallet": ["./packages/plugins/Wallet/src"] }, From edc6c2fd73372e8cb7c6ad6205c6b72c9d9bd9f3 Mon Sep 17 00:00:00 2001 From: Randolph <840094513@qq.com> Date: Wed, 6 Apr 2022 18:16:53 +0800 Subject: [PATCH 31/42] feat: update pnpm-lock file --- pnpm-lock.yaml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a1e1059cffde..7a0111f56c1b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -634,7 +634,7 @@ importers: '@masknet/plugin-infra': link:../../plugin-infra '@masknet/shared': link:../../shared '@masknet/shared-base': link:../../shared-base - react-use: 17.3.2_react-dom@18.0.0+react@18.0.0 + react-use: 17.3.2_581fa33d3647c30d8078674dcd1b240a packages/plugins/CyberConnect: specifiers: @@ -20747,7 +20747,6 @@ packages: /minimist/1.2.6: resolution: {integrity: sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==} - dev: false /minipass-collect/1.0.2: resolution: {integrity: sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==} From 44283f05e945945921b38b5465de6d29807b0623 Mon Sep 17 00:00:00 2001 From: lelenei <72531217+lelenei@users.noreply.github.com> Date: Wed, 6 Apr 2022 22:17:08 +0800 Subject: [PATCH 32/42] fix: can't auto close dialog when lost focus (#5977) * fix: auto close dialog when lost focus * fix: reply review * fix: reply review * fix: reply review * fix: tradeview position * fix: remove icon section --- .../SNSAdaptor/trending/TrendingPopper.tsx | 17 ++++++++++------- packages/plugins/CrossChainBridge/src/base.ts | 1 - 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/packages/mask/src/plugins/Trader/SNSAdaptor/trending/TrendingPopper.tsx b/packages/mask/src/plugins/Trader/SNSAdaptor/trending/TrendingPopper.tsx index d8d7af77826e..27642f95a731 100644 --- a/packages/mask/src/plugins/Trader/SNSAdaptor/trending/TrendingPopper.tsx +++ b/packages/mask/src/plugins/Trader/SNSAdaptor/trending/TrendingPopper.tsx @@ -13,6 +13,8 @@ export interface TrendingPopperProps { PopperProps?: Partial } +const TIMEOUT = 1500 + export function TrendingPopper(props: TrendingPopperProps) { const popperRef = useRef<{ update(): void } | null>(null) const [freezed, setFreezed] = useState(false) // disable any click @@ -21,6 +23,8 @@ export function TrendingPopper(props: TrendingPopperProps) { const [type, setType] = useState() const [anchorEl, setAnchorEl] = useState(null) const [availableDataProviders, setAvailableDataProviders] = useState([]) + const popper = useRef(null) + const [mouseIn, setMouseIn] = useState(false) // #region select token and provider dialog could be open by trending view const onFreezed = useCallback((ev) => setFreezed(ev.open), []) @@ -66,14 +70,12 @@ export function TrendingPopper(props: TrendingPopperProps) { // close popper if scroll out of visual screen const position = useWindowScroll() useEffect(() => { - if (!anchorEl) return - const { top } = anchorEl.getBoundingClientRect() - if ( - top < 0 || // out off top bound - top > document.documentElement.clientHeight // out off bottom bound - ) + if (!popper.current) return + const { top, height } = popper.current?.getBoundingClientRect() + if ((top < 0 && -1 * top > height) || top > document.documentElement.clientHeight) + // out off bottom bound setAnchorEl(null) - }, [anchorEl, Math.floor(position.y / 50)]) + }, [popper, Math.floor(position.y / 50)]) // #endregion if (locked) return null @@ -84,6 +86,7 @@ export function TrendingPopper(props: TrendingPopperProps) { if (!freezed) setAnchorEl(null) }}> Date: Wed, 6 Apr 2022 14:12:29 +0800 Subject: [PATCH 33/42] fix: hidden web3 tab page (#6021) --- .../InjectedComponents/ProfileTabContent.tsx | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/packages/mask/src/components/InjectedComponents/ProfileTabContent.tsx b/packages/mask/src/components/InjectedComponents/ProfileTabContent.tsx index fa30e0d04506..feeaeba8c65f 100644 --- a/packages/mask/src/components/InjectedComponents/ProfileTabContent.tsx +++ b/packages/mask/src/components/InjectedComponents/ProfileTabContent.tsx @@ -13,6 +13,7 @@ import { first } from 'lodash-unified' import { useEffect, useMemo, useState } from 'react' import { useUpdateEffect } from 'react-use' import { activatedSocialNetworkUI } from '../../social-network' +import { isTwitter } from '../../social-network-adaptor/twitter.com/base' import { MaskMessages } from '../../utils' import { useLocationChange } from '../../utils/hooks/useLocationChange' import { useCurrentVisitingIdentity, useLastRecognizedIdentity } from '../DataSource/useActivatedUI' @@ -57,6 +58,7 @@ export function ProfileTabContent(props: ProfileTabContentProps) { platform as NextIDPlatform, identity.identifier.userId, ) + const currentAccountNotConnectPersona = currentIdentity.identifier.userId === identity.identifier.userId && personaList.findIndex((persona) => persona?.persona === currentConnectedPersona?.publicHexKey) === -1 @@ -84,6 +86,7 @@ export function ProfileTabContent(props: ProfileTabContentProps) { return a.priority - z.priority }) + const selectedTabComputed = selectedTab ?? first(tabs) useLocationChange(() => { @@ -107,11 +110,12 @@ export function ProfileTabContent(props: ProfileTabContentProps) { }, [identity]) const ContentComponent = useMemo(() => { - const tab = currentAccountNotConnectPersona - ? tabs?.find((tab) => tab?.pluginID === PluginId.NextID)?.ID - : selectedTabComputed?.ID + const tab = + isTwitter(activatedSocialNetworkUI) && currentAccountNotConnectPersona + ? tabs?.find((tab) => tab?.pluginID === PluginId.NextID)?.ID + : selectedTabComputed?.ID return getTabContent(tab ?? '') - }, [selectedTabComputed, identity.identifier]) + }, [selectedTabComputed?.ID, identity.identifier.userId]) if (hidden) return null From e718d5cdb21ed3a6b5898ed4350844e55ef5ffc4 Mon Sep 17 00:00:00 2001 From: lelenei <72531217+lelenei@users.noreply.github.com> Date: Sat, 2 Apr 2022 11:19:26 +0800 Subject: [PATCH 34/42] fix(instagram): can't open web3 tab (#6011) --- .../mask/src/components/InjectedComponents/ProfileTab.tsx | 4 +++- .../instagram.com/injection/ProfileTab.tsx | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/mask/src/components/InjectedComponents/ProfileTab.tsx b/packages/mask/src/components/InjectedComponents/ProfileTab.tsx index 8a45f7620a25..5308f094be12 100644 --- a/packages/mask/src/components/InjectedComponents/ProfileTab.tsx +++ b/packages/mask/src/components/InjectedComponents/ProfileTab.tsx @@ -2,6 +2,8 @@ import { ReactElement, useCallback, useState } from 'react' import classnames from 'classnames' import { Typography } from '@mui/material' import { MaskMessages, useMatchXS, useLocationChange } from '../../utils' +import { isTwitter } from '../../social-network-adaptor/twitter.com/base' +import { activatedSocialNetworkUI } from '../../social-network' export interface ProfileTabProps extends withClasses<'tab' | 'button' | 'selected'> { clear(): void @@ -20,7 +22,7 @@ export function ProfileTab(props: ProfileTabProps) { const onClick = useCallback(() => { // Change the url hashtag to trigger `locationchange` event from e.g. 'hostname/medias#web3 => hostname/medias' - location.assign('#web3') + isTwitter(activatedSocialNetworkUI) && location.assign('#web3') MaskMessages.events.profileTabUpdated.sendToLocal({ show: true }) setActive(true) clear() diff --git a/packages/mask/src/social-network-adaptor/instagram.com/injection/ProfileTab.tsx b/packages/mask/src/social-network-adaptor/instagram.com/injection/ProfileTab.tsx index 4bca7610b3c3..f52a94f53e5c 100644 --- a/packages/mask/src/social-network-adaptor/instagram.com/injection/ProfileTab.tsx +++ b/packages/mask/src/social-network-adaptor/instagram.com/injection/ProfileTab.tsx @@ -151,7 +151,7 @@ export function ProfileTabAtInstagram() { ele.style.display = '' } } - const clear = async () => { + const clear = () => { const style = getStyleProps({ activeColor, color }) const activeTab = searchProfileActiveTabSelector().evaluate() if (activeTab?.style) { From df58c2dfbb7393108b2e9c477fe45fa618a04824 Mon Sep 17 00:00:00 2001 From: Randolph314 <97870249+Randolph314@users.noreply.github.com> Date: Thu, 7 Apr 2022 14:05:32 +0800 Subject: [PATCH 35/42] feat: delete mask bridge entry (#6037) Co-authored-by: Randolph <840094513@qq.com> --- .../src/plugins/MaskBox/SNSAdaptor/index.tsx | 13 ------------- .../mask/src/plugins/MaskBox/assets/bridge.png | Bin 2326 -> 0 bytes 2 files changed, 13 deletions(-) delete mode 100644 packages/mask/src/plugins/MaskBox/assets/bridge.png diff --git a/packages/mask/src/plugins/MaskBox/SNSAdaptor/index.tsx b/packages/mask/src/plugins/MaskBox/SNSAdaptor/index.tsx index 52c5b95dbfee..a4ef2807ea8a 100644 --- a/packages/mask/src/plugins/MaskBox/SNSAdaptor/index.tsx +++ b/packages/mask/src/plugins/MaskBox/SNSAdaptor/index.tsx @@ -29,19 +29,6 @@ const sns: Plugin.SNSAdaptor.Definition = { return }, ApplicationEntries: [ - { - RenderEntryComponent({ disabled }) { - return ( - openWindow('https://bridge.mask.io/#/')} - /> - ) - }, - defaultSortingPriority: 5, - }, { RenderEntryComponent({ disabled }) { return ( diff --git a/packages/mask/src/plugins/MaskBox/assets/bridge.png b/packages/mask/src/plugins/MaskBox/assets/bridge.png deleted file mode 100644 index e2a12cd3cc726c5ec6ee1e6ea0780f6861b8d83b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2326 zcmX9;3pms58(ul*kEMymFlJGc%O1+d9L@p-ehM-ip)0THW&;hV`ppa3hlwr zIwvUtA?;9eqcbY>%q-kp$r7g~`9gbab3VasHD-w2QH(K`0BJjpA~<*FY}5;~Q8yaE@ngU%JlJIeHkqP* zX8>EQ)u^r}D-2vZ37X=pzUczTRe`g+fa7XEfBTXQKY+7dI@B@MpdSEPCu7d$-SRQu zlnOvaJ0lyQt8pGP05SNURS!*8c;UQ#`NEN&6;E`@O>oW&IHioK_pe`c!L)b)w!4*M z`p|we;5!oDy5Hoh4scyoi|0VJ=&{Ci010r-`T$#On}*-4gL(^4rlS(mXKdYvAJM^f z9|VQ=sH9G?=P=NI(46oQNZ5{PcGs-;FJEwULN+j_%(aeBs%IBzwI9}X{tD!&>f3(- zx@?E=9hn-q>QO~L;GGvK@eG3wC8s%{g>diW|F>JR5 zI8FuLkpNTN0YbOSn1O-)AovRZYSC2%a$i0PR_lRe9gT{(-Q5-;B@6(1)2Aa`9go6> z;?%kD5H6QH&!rE|lj4DjH7Jx`zx`+HhS+kW?}^Y+ef$ShhP2-#k~t~ng{ny7ZYAOK z^_kN75^27EO`{dk&d!Z#Y56F=AD_=>erR$MYicUU$Uu2`+~#uCm$}YRcK2#!$W!c= zoi*8w;WKl8EJTHdXblXGI%w_akRsokTo|d8V{Cud(8$Q^%(38r?8eP!7Z9LrWMuS> z+Z8<&Q+?Yb=gE3ucV66Zarj)_{Ci2zNh`zIQtCe#D&QOlFF*7xtj-vjTkifKbK}IF zn(U9>VL^th`wk|1bfq?|Gm04U2|Av+YV?(h8$pK4OG{Y}x+sfkHA1brf0(*nC_gHR(k_PW9 zR&^|@Vq0|3(e3PMNk9DB@n>-rZ`P|gEY|1qtAZJKy@lU#XeKr@;Lgb9+f{HuTV)Iv z@3uaxOswK2Qxkh%ky_hg>2C&FrcmcuS83lX?=Wy5+GUY>u35>fFJ$&iY(s5G4XgJY zn|&YqFt*@Q(gJcBFusdudI?{lL`zQFc;${Q#^WxsrQTO7i>$nnEQSRPUajQdnhjHb zBWw*le7=+PzEw@$%K7#-Xgf7!nXWTO?+opWltAY^c)*M=?mHc;r&+H05ohB~_KwE3 zmdwj3RbTL8iWJMG(QcGX?YPF15VvCZbF#1_FXK%(+OkS>y;-70<^H?ou%9OVM%GMM z7F9=r16OV)J?aheRV$n>xh2{^kc<`>3P@^E=}*!aEXS6ZLxeNqIgG2+1S3Cvm0ohd z459WOXDMfmH;&_uR1taOL$$_cS(m18!|(OI6^8eO^8DnUi8_r}%g=~N2QaP|27HO7 zq{7P{KAq2NWn6PNPqQaTlt)S3-1pn2ZB!s(S7qCWJRQYLp#KoVB6~z6r|74O@|Kl-4XGMsa&)7`D-$ozU^B%om|d8MT}rJWUv@it z;O+MKTvn(sBgzt|o8NR{=ecpo5ArwC<(rYC!W%^2<*J)kjFN;oE^W;lol=jOlz;LR zwaj1Q_kXw`t!H~O6`mGWE;eA{9j;Fk86T*L$oWxOEF!p>r8yUYZ?Szp5-M?$I$y}o zHL!H~6&-cKz0YRLS)aUb1jMKb+NYCQ`Vi)c8dNi;u)KFn?%K7@y`N;oYf~Jd#ftkU zhos!`LF`z;SW<>dqqYiCnXCikyr=LImOM7AZPU3*5V5$KbaW1*QVYPsmGk|4&UA^v7wB^}@#G0dMo{a&`xzyWm zb^l+A3);WpP; zO>gM@>q6}~ywdAOV)y0FBiBhKTi5;Jn2V#1lq%B!oV zPqYV_n!=pZ)5-)=1u?oQPu=)b7acjzXBC!X@g}0uiuVplSGp?%8}K8=KLSA^sV*?l zM5Po@(dW%IH->fC3kUXG@Awl^z;gEh>rFQ<1wY9NKI~}}eKt5viF-zKgaMc@W}I3t g?RzZ?eg4px5g$G^XSTaI9 Date: Thu, 7 Apr 2022 15:32:07 +0800 Subject: [PATCH 36/42] fix: remove suspend throw --- packages/mask/src/plugins/ITO/SNSAdaptor/ITO.tsx | 9 +++++---- packages/mask/src/plugins/ITO/SNSAdaptor/ShareDialog.tsx | 5 +++-- .../plugins/ITO/SNSAdaptor/hooks/usePoolBackground.ts | 6 ++++++ packages/shared-base/src/utils/getAssetAsBlobURL.ts | 4 ++-- 4 files changed, 16 insertions(+), 8 deletions(-) create mode 100644 packages/mask/src/plugins/ITO/SNSAdaptor/hooks/usePoolBackground.ts diff --git a/packages/mask/src/plugins/ITO/SNSAdaptor/ITO.tsx b/packages/mask/src/plugins/ITO/SNSAdaptor/ITO.tsx index 2e910ff9d7fb..5d9940820e1a 100644 --- a/packages/mask/src/plugins/ITO/SNSAdaptor/ITO.tsx +++ b/packages/mask/src/plugins/ITO/SNSAdaptor/ITO.tsx @@ -29,7 +29,7 @@ import { usePostLink } from '../../../components/DataSource/usePostInfo' import ActionButton from '../../../extension/options-page/DashboardComponents/ActionButton' import { TokenIcon } from '@masknet/shared' import { activatedSocialNetworkUI } from '../../../social-network' -import { getAssetAsBlobURL, getTextUILength, useI18N } from '../../../utils' +import { getTextUILength, useI18N } from '../../../utils' import { WalletMessages } from '../../Wallet/messages' import { ITO_EXCHANGE_RATION_MAX, MSG_DELIMITER, TIME_WAIT_BLOCKCHAIN } from '../constants' import { sortTokens } from './helpers' @@ -39,6 +39,7 @@ import { useDestructCallback } from './hooks/useDestructCallback' import { useIfQualified } from './hooks/useIfQualified' import { usePoolTradeInfo } from './hooks/usePoolTradeInfo' import { checkRegionRestrict, decodeRegionCode, useIPRegion } from './hooks/useRegion' +import { usePoolBackground } from './hooks/usePoolBackground' import { ITO_Status, JSON_PayloadInMask } from '../types' import { StyledLinearProgress } from './StyledLinearProgress' import { SwapGuide, SwapStatus } from './SwapGuide' @@ -233,7 +234,7 @@ export function ITO(props: ITO_Props) { const [claimDialogStatus, setClaimDialogStatus] = useState(SwapStatus.Remind) // assets - const PoolBackground = getAssetAsBlobURL(new URL('../assets/pool-background.jpg', import.meta.url)) + const { value: PoolBackground } = usePoolBackground() const { pid, payload } = props const { regions: defaultRegions = '-' } = props.payload @@ -853,7 +854,7 @@ export function ITO(props: ITO_Props) { export function ITO_Loading() { const { t } = useI18N() - const PoolBackground = getAssetAsBlobURL(new URL('../assets/pool-loading-background.jpg', import.meta.url)) + const { value: PoolBackground } = usePoolBackground() const { classes } = useStyles({}) return (
@@ -872,7 +873,7 @@ export function ITO_Loading() { export function ITO_Error({ retryPoolPayload }: { retryPoolPayload: () => void }) { const { t } = useI18N() const { classes } = useStyles({}) - const PoolBackground = getAssetAsBlobURL(new URL('../assets/pool-loading-background.jpg', import.meta.url)) + const { value: PoolBackground } = usePoolBackground() return ( ({ shareWrapper: { @@ -62,7 +63,7 @@ export interface ShareDialogProps extends withClasses<'root'> { } export function ShareDialog(props: ShareDialogProps) { - const ShareBackground = getAssetAsBlobURL(new URL('../assets/share-background.jpg', import.meta.url)) + const { value: ShareBackground } = usePoolBackground() const { t } = useI18N() const classes = useStylesExtends(useStyles(), {}) const { token, actualSwapAmount, shareSuccessText, onClose } = props diff --git a/packages/mask/src/plugins/ITO/SNSAdaptor/hooks/usePoolBackground.ts b/packages/mask/src/plugins/ITO/SNSAdaptor/hooks/usePoolBackground.ts new file mode 100644 index 000000000000..8b40e0b945aa --- /dev/null +++ b/packages/mask/src/plugins/ITO/SNSAdaptor/hooks/usePoolBackground.ts @@ -0,0 +1,6 @@ +import { useAsync } from 'react-use' +import { getAssetAsBlobURL } from '../../../../utils' + +export function usePoolBackground() { + return useAsync(async () => getAssetAsBlobURL(new URL('../../assets/pool-background.jpg', import.meta.url)), []) +} diff --git a/packages/shared-base/src/utils/getAssetAsBlobURL.ts b/packages/shared-base/src/utils/getAssetAsBlobURL.ts index 78e1db5cd33d..408351af8996 100644 --- a/packages/shared-base/src/utils/getAssetAsBlobURL.ts +++ b/packages/shared-base/src/utils/getAssetAsBlobURL.ts @@ -3,9 +3,9 @@ const cache = new Map() * Fetch a file and turn it into blob URL. * This function must run in React concurrent mode. */ -export function getAssetAsBlobURL(url: string | URL, fetcher: (url: string) => Promise) { +export async function getAssetAsBlobURL(url: string | URL, fetcher: (url: string) => Promise) { url = url.toString() - if (!cache.has(url)) throw toBlob(url, fetcher) + if (!cache.has(url)) return toBlob(url, fetcher) return cache.get(url)! } async function toBlob(url: string, fetcher: (url: string) => Promise) { From cf327532239f3aac97189811821840506dd02ff6 Mon Sep 17 00:00:00 2001 From: Hom Date: Thu, 7 Apr 2022 15:35:49 +0800 Subject: [PATCH 37/42] feat: persona QR code (#5990) (cherry picked from commit f1807ca051e30b606f4283a88a079534978fd076) --- .../src/pages/SignUp/steps/PreviewDialog.tsx | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/packages/dashboard/src/pages/SignUp/steps/PreviewDialog.tsx b/packages/dashboard/src/pages/SignUp/steps/PreviewDialog.tsx index 01770a118261..86828c94d9e3 100644 --- a/packages/dashboard/src/pages/SignUp/steps/PreviewDialog.tsx +++ b/packages/dashboard/src/pages/SignUp/steps/PreviewDialog.tsx @@ -3,7 +3,7 @@ import { makeStyles, MaskDialog, MaskColorVar, MaskLightTheme, useCustomSnackbar import { Box, Button, DialogContent, ThemeProvider, Typography } from '@mui/material' import { MnemonicReveal } from '../../../components/Mnemonic' import { MiniMaskIcon, InfoIcon, CopyIcon } from '@masknet/icons' -import { ForwardedRef, forwardRef, useEffect, useRef } from 'react' +import { ForwardedRef, forwardRef, useEffect, useMemo, useRef } from 'react' import { useReactToPrint } from 'react-to-print' import { toJpeg } from 'html-to-image' import { WatermarkURL } from '../../../assets' @@ -107,6 +107,11 @@ const ComponentToPrint = forwardRef((props: PreviewDialogProps, ref: ForwardedRe const [state, copyToClipboard] = useCopyToClipboard() const { showSnackbar } = useCustomSnackbar() + const qrValue = useMemo(() => { + const main = words?.length ? `mnemonic/${btoa(words.join(' '))}` : `privatekey/${privateKey}` + return `mask://persona/${main}?nickname=${personaName}` + }, [words?.join(), privateKey, personaName]) + useEffect(() => { if (state.value) { showSnackbar(t.personas_export_persona_copy_success(), { variant: 'success' }) @@ -157,13 +162,7 @@ const ComponentToPrint = forwardRef((props: PreviewDialogProps, ref: ForwardedRe - + {words?.length ? ( <> From 709da7bc09ac47d3d26f1e1b16214806dc0b1fa1 Mon Sep 17 00:00:00 2001 From: Randolph314 <97870249+Randolph314@users.noreply.github.com> Date: Thu, 7 Apr 2022 20:21:09 +0800 Subject: [PATCH 38/42] feat: change cross chain config (#6045) * feat: change plugin config * feat: change code style Co-authored-by: Randolph <840094513@qq.com> --- packages/plugins/CrossChainBridge/src/SNSAdaptor/MaskIcon.tsx | 4 ++++ packages/plugins/CrossChainBridge/src/SNSAdaptor/index.tsx | 2 +- packages/plugins/CrossChainBridge/src/base.ts | 4 ++-- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/packages/plugins/CrossChainBridge/src/SNSAdaptor/MaskIcon.tsx b/packages/plugins/CrossChainBridge/src/SNSAdaptor/MaskIcon.tsx index f3027591ddcf..5bf482a61c53 100644 --- a/packages/plugins/CrossChainBridge/src/SNSAdaptor/MaskIcon.tsx +++ b/packages/plugins/CrossChainBridge/src/SNSAdaptor/MaskIcon.tsx @@ -8,6 +8,7 @@ export function ArbitrumOneBridgeIcon({ size = 36 }) { /> ) } + export function BobaBridgeIcon({ size = 36 }) { return ( ) } + export function CBridgeIcon({ size = 36 }) { return ( ) } + export function PolygonBridgeIcon({ size = 36 }) { return ( ) } + export function RainbowBridgeIcon({ size = 36 }) { return ( ) }, - defaultSortingPriority: 2, + defaultSortingPriority: 4, }, ], } diff --git a/packages/plugins/CrossChainBridge/src/base.ts b/packages/plugins/CrossChainBridge/src/base.ts index 790a217a8f6e..a593b93d23aa 100644 --- a/packages/plugins/CrossChainBridge/src/base.ts +++ b/packages/plugins/CrossChainBridge/src/base.ts @@ -10,8 +10,8 @@ export const base: Plugin.Shared.Definition = { enableRequirement: { architecture: { app: false, web: true }, networks: { type: 'opt-out', networks: {} }, - target: 'beta', + target: 'stable', }, - experimentalMark: true, + experimentalMark: false, i18n: languages, } From b70f307da69672a802ca5dcce44521f94c782ce0 Mon Sep 17 00:00:00 2001 From: Lantt Date: Fri, 8 Apr 2022 10:54:19 +0800 Subject: [PATCH 39/42] feat: add token security rules (#6039) * feat: add rules * refactor: convert security type to enum * fix: warning icon * refactor: remove template code --- .../src/SNSAdaptor/components/Common.tsx | 5 +- .../GoPlusSecurity/src/SNSAdaptor/rules.ts | 155 +++++++++++------- .../GoPlusSecurity/src/locales/en-US.json | 10 +- 3 files changed, 110 insertions(+), 60 deletions(-) diff --git a/packages/plugins/GoPlusSecurity/src/SNSAdaptor/components/Common.tsx b/packages/plugins/GoPlusSecurity/src/SNSAdaptor/components/Common.tsx index df7c2abf0130..c225c755e00e 100644 --- a/packages/plugins/GoPlusSecurity/src/SNSAdaptor/components/Common.tsx +++ b/packages/plugins/GoPlusSecurity/src/SNSAdaptor/components/Common.tsx @@ -1,5 +1,5 @@ import type { SecurityAPI } from '@masknet/web3-providers' -import { InfoIcon, RiskIcon, SuccessIcon } from '@masknet/icons' +import { NextIdPersonaWarningIcon, RiskIcon, SuccessIcon } from '@masknet/icons' import { memo, ReactNode } from 'react' import { Stack } from '@mui/material' import type { useI18N } from '../../locales' @@ -41,7 +41,8 @@ export const DefineMapping: DefineMapping = { i18nKey: 'medium_risk', titleColor: '#FFB915', bgColor: 'rgba(255, 185, 21, 0.1)', - icon: (size: number) => , + // TODO: Merge duplicate icon in a another PR. + icon: (size: number) => , }, [SecurityMessageLevel.Safe]: { i18nKey: 'low_risk', diff --git a/packages/plugins/GoPlusSecurity/src/SNSAdaptor/rules.ts b/packages/plugins/GoPlusSecurity/src/SNSAdaptor/rules.ts index 0f66eb822cc7..8c31a6f1e438 100644 --- a/packages/plugins/GoPlusSecurity/src/SNSAdaptor/rules.ts +++ b/packages/plugins/GoPlusSecurity/src/SNSAdaptor/rules.ts @@ -4,8 +4,14 @@ import parseInt from 'lodash-es/parseInt' export type I18nOptions = 'rate' | 'quantity' +enum SecurityType { + Contract = 'contract-security', + Transaction = 'transaction-security', + Info = 'info-security', +} + export interface SecurityMessage { - type: 'contract-security' | 'transaction-security' + type: SecurityType level: SecurityMessageLevel condition(info: TokenSecurity): boolean titleKey: keyof ReturnType @@ -15,96 +21,97 @@ export interface SecurityMessage { } const percentageToNumber = (value?: string) => parseInt((value ?? '').replace('%', '')) * 100 +const isUnset = (name: keyof TokenSecurity) => (info: TokenSecurity) => info[name] === undefined export const SecurityMessages: SecurityMessage[] = [ // open source { - type: 'contract-security', + type: SecurityType.Contract, level: SecurityMessageLevel.Safe, condition: (info: TokenSecurity) => info.is_open_source === '1', titleKey: 'risk_contract_source_code_verified_title', messageKey: 'risk_contract_source_code_verified_body', - shouldHide: (info: TokenSecurity) => info.is_open_source === undefined, + shouldHide: isUnset('is_open_source'), }, { - type: 'contract-security', + type: SecurityType.Contract, level: SecurityMessageLevel.High, condition: (info: TokenSecurity) => info.is_open_source === '0', titleKey: 'risk_contract_source_code_not_verified_title', messageKey: 'risk_contract_source_code_not_verified_body', - shouldHide: (info: TokenSecurity) => info.is_open_source === undefined, + shouldHide: isUnset('is_open_source'), }, // proxy { - type: 'contract-security', + type: SecurityType.Contract, level: SecurityMessageLevel.Medium, condition: (info: TokenSecurity) => info.is_proxy === '1', titleKey: 'risk_proxy_contract_title', messageKey: 'risk_proxy_contract_body', - shouldHide: (info: TokenSecurity) => info.is_proxy === undefined, + shouldHide: isUnset('is_proxy'), }, { - type: 'contract-security', + type: SecurityType.Contract, level: SecurityMessageLevel.Safe, condition: (info: TokenSecurity) => info.is_proxy === '0', titleKey: 'risk_no_proxy_title', messageKey: 'risk_no_proxy_body', - shouldHide: (info: TokenSecurity) => info.is_proxy === undefined, + shouldHide: isUnset('is_proxy'), }, // mint { - type: 'contract-security', + type: SecurityType.Contract, level: SecurityMessageLevel.Safe, condition: (info: TokenSecurity) => info.is_mintable === '0', titleKey: 'risk_no_mint_function_title', messageKey: 'risk_no_mint_function_body', - shouldHide: (info: TokenSecurity) => info.is_mintable === undefined, + shouldHide: isUnset('is_mintable'), }, { - type: 'contract-security', + type: SecurityType.Contract, level: SecurityMessageLevel.Medium, condition: (info: TokenSecurity) => info.is_mintable === '1', titleKey: 'risk_mint_function_title', messageKey: 'risk_mint_function_body', - shouldHide: (info: TokenSecurity) => info.is_mintable === undefined, + shouldHide: isUnset('is_mintable'), }, // owner change balance { - type: 'contract-security', + type: SecurityType.Contract, level: SecurityMessageLevel.Safe, condition: (info: TokenSecurity) => info.owner_change_balance === '0', titleKey: 'risk_owner_can_not_change_balance_title', messageKey: 'risk_owner_can_not_change_balance_body', - shouldHide: (info: TokenSecurity) => info.owner_change_balance === undefined, + shouldHide: isUnset('owner_change_balance'), }, { - type: 'contract-security', + type: SecurityType.Contract, level: SecurityMessageLevel.Medium, condition: (info: TokenSecurity) => info.owner_change_balance === '1', titleKey: 'risk_owner_change_balance_title', messageKey: 'risk_owner_change_balance_body', - shouldHide: (info: TokenSecurity) => info.owner_change_balance === undefined, + shouldHide: isUnset('owner_change_balance'), }, // can take back ownership { - type: 'contract-security', + type: SecurityType.Contract, level: SecurityMessageLevel.Safe, condition: (info: TokenSecurity) => info.can_take_back_ownership === '0', titleKey: 'risk_no_can_take_back_ownership_title', messageKey: 'risk_no_can_take_back_ownership_body', - shouldHide: (info: TokenSecurity) => info.can_take_back_ownership === undefined, + shouldHide: isUnset('can_take_back_ownership'), }, { - type: 'contract-security', + type: SecurityType.Contract, level: SecurityMessageLevel.Medium, condition: (info: TokenSecurity) => info.can_take_back_ownership === '1', titleKey: 'risk_can_take_back_ownership_title', messageKey: 'risk_can_take_back_ownership_body', - shouldHide: (info: TokenSecurity) => info.can_take_back_ownership === undefined, + shouldHide: isUnset('can_take_back_ownership'), }, // buy tax { - type: 'transaction-security', + type: SecurityType.Transaction, level: SecurityMessageLevel.Safe, condition: (info: TokenSecurity) => percentageToNumber(info.buy_tax) < 10, titleKey: 'risk_buy_tax_title', @@ -113,10 +120,10 @@ export const SecurityMessages: SecurityMessage[] = [ rate: `${percentageToNumber(info.buy_tax)}%`, quantity: '', }), - shouldHide: (info: TokenSecurity) => info.buy_tax === undefined, + shouldHide: isUnset('buy_tax'), }, { - type: 'contract-security', + type: SecurityType.Transaction, level: SecurityMessageLevel.Medium, condition: (info: TokenSecurity) => percentageToNumber(info.buy_tax) >= 10 && percentageToNumber(info.buy_tax) < 50, @@ -126,10 +133,10 @@ export const SecurityMessages: SecurityMessage[] = [ rate: `${percentageToNumber(info.buy_tax)}%`, quantity: '', }), - shouldHide: (info: TokenSecurity) => info.buy_tax === undefined, + shouldHide: isUnset('buy_tax'), }, { - type: 'contract-security', + type: SecurityType.Transaction, level: SecurityMessageLevel.High, condition: (info: TokenSecurity) => percentageToNumber(info.buy_tax) >= 50, titleKey: 'risk_buy_tax_title', @@ -138,11 +145,11 @@ export const SecurityMessages: SecurityMessage[] = [ rate: `${percentageToNumber(info.buy_tax)}%`, quantity: '', }), - shouldHide: (info: TokenSecurity) => info.buy_tax === undefined, + shouldHide: isUnset('buy_tax'), }, // sell tax { - type: 'transaction-security', + type: SecurityType.Transaction, level: SecurityMessageLevel.Safe, condition: (info: TokenSecurity) => percentageToNumber(info.sell_tax) < 10, titleKey: 'risk_sell_tax_title', @@ -151,10 +158,10 @@ export const SecurityMessages: SecurityMessage[] = [ rate: `${percentageToNumber(info.sell_tax)}%`, quantity: '', }), - shouldHide: (info: TokenSecurity) => info.sell_tax === undefined, + shouldHide: isUnset('sell_tax'), }, { - type: 'contract-security', + type: SecurityType.Transaction, level: SecurityMessageLevel.Medium, condition: (info: TokenSecurity) => percentageToNumber(info.sell_tax) >= 10 && percentageToNumber(info.sell_tax) < 50, @@ -164,10 +171,10 @@ export const SecurityMessages: SecurityMessage[] = [ rate: `${percentageToNumber(info.sell_tax)}%`, quantity: '', }), - shouldHide: (info: TokenSecurity) => info.sell_tax === undefined, + shouldHide: isUnset('sell_tax'), }, { - type: 'contract-security', + type: SecurityType.Transaction, level: SecurityMessageLevel.High, condition: (info: TokenSecurity) => percentageToNumber(info.sell_tax) >= 50, titleKey: 'risk_sell_tax_title', @@ -176,108 +183,142 @@ export const SecurityMessages: SecurityMessage[] = [ rate: `${percentageToNumber(info.sell_tax)}%`, quantity: '', }), - shouldHide: (info: TokenSecurity) => info.sell_tax === undefined, + shouldHide: isUnset('sell_tax'), }, // honeypot { - type: 'transaction-security', + type: SecurityType.Transaction, level: SecurityMessageLevel.Safe, condition: (info: TokenSecurity) => info.is_honeypot === '0', titleKey: 'risk_is_not_honeypot_title', messageKey: 'risk_is_not_honeypot_body', - shouldHide: (info: TokenSecurity) => info.is_honeypot === undefined, + shouldHide: isUnset('is_honeypot'), }, { - type: 'contract-security', + type: SecurityType.Transaction, level: SecurityMessageLevel.High, condition: (info: TokenSecurity) => info.is_honeypot === '1', titleKey: 'risk_is_honeypot_title', messageKey: 'risk_is_honeypot_body', - shouldHide: (info: TokenSecurity) => info.is_honeypot === undefined, + shouldHide: isUnset('is_honeypot'), }, // transfer_pausable { - type: 'transaction-security', + type: SecurityType.Transaction, level: SecurityMessageLevel.Safe, condition: (info: TokenSecurity) => info.transfer_pausable === '0', titleKey: 'risk_no_code_transfer_pausable_title', messageKey: 'risk_no_code_transfer_pausable_title', - shouldHide: (info: TokenSecurity) => info.transfer_pausable === undefined, + shouldHide: isUnset('transfer_pausable'), }, { - type: 'contract-security', + type: SecurityType.Transaction, level: SecurityMessageLevel.Medium, condition: (info: TokenSecurity) => info.transfer_pausable === '1', titleKey: 'risk_transfer_pausable_title', messageKey: 'risk_transfer_pausable_body', - shouldHide: (info: TokenSecurity) => info.transfer_pausable === undefined, + shouldHide: isUnset('transfer_pausable'), }, // anti whale { - type: 'transaction-security', + type: SecurityType.Transaction, level: SecurityMessageLevel.Safe, condition: (info: TokenSecurity) => info.is_anti_whale === '0', titleKey: 'risk_is_no_anti_whale_title', messageKey: 'risk_is_no_anti_whale_body', - shouldHide: (info: TokenSecurity) => info.is_anti_whale === undefined, + shouldHide: isUnset('is_anti_whale'), }, { - type: 'contract-security', + type: SecurityType.Transaction, level: SecurityMessageLevel.Medium, condition: (info: TokenSecurity) => info.is_anti_whale === '1', titleKey: 'risk_is_anti_whale_title', messageKey: 'risk_is_anti_whale_body', - shouldHide: (info: TokenSecurity) => info.is_anti_whale === undefined, + shouldHide: isUnset('is_anti_whale'), }, // slippage modifiable { - type: 'transaction-security', + type: SecurityType.Transaction, level: SecurityMessageLevel.Safe, condition: (info: TokenSecurity) => info.slippage_modifiable === '0', titleKey: 'risk_not_slippage_modifiable_title', messageKey: 'risk_not_slippage_modifiable_body', - shouldHide: (info: TokenSecurity) => info.slippage_modifiable === undefined, + shouldHide: isUnset('slippage_modifiable'), }, { - type: 'contract-security', + type: SecurityType.Transaction, level: SecurityMessageLevel.Medium, condition: (info: TokenSecurity) => info.slippage_modifiable === '1', titleKey: 'risk_slippage_modifiable_title', messageKey: 'risk_slippage_modifiable_body', - shouldHide: (info: TokenSecurity) => info.slippage_modifiable === undefined, + shouldHide: isUnset('slippage_modifiable'), }, // black list { - type: 'transaction-security', + type: SecurityType.Transaction, level: SecurityMessageLevel.Safe, condition: (info: TokenSecurity) => info.is_blacklisted === '0', titleKey: 'risk_not_is_blacklisted_title', messageKey: 'risk_not_is_blacklisted_body', - shouldHide: (info: TokenSecurity) => info.is_blacklisted === undefined, + shouldHide: isUnset('is_blacklisted'), }, { - type: 'contract-security', + type: SecurityType.Transaction, level: SecurityMessageLevel.Medium, condition: (info: TokenSecurity) => info.is_blacklisted === '1', titleKey: 'risk_is_blacklisted_title', messageKey: 'risk_is_blacklisted_body', - shouldHide: (info: TokenSecurity) => info.is_blacklisted === undefined, + shouldHide: isUnset('is_blacklisted'), }, // white list { - type: 'transaction-security', + type: SecurityType.Transaction, level: SecurityMessageLevel.Safe, condition: (info: TokenSecurity) => info.is_whitelisted === '0', titleKey: 'risk_not_is_whitelisted_title', messageKey: 'risk_not_is_whitelisted_body', - shouldHide: (info: TokenSecurity) => info.is_whitelisted === undefined, + shouldHide: isUnset('is_whitelisted'), }, { - type: 'contract-security', + type: SecurityType.Transaction, level: SecurityMessageLevel.Medium, condition: (info: TokenSecurity) => info.is_whitelisted === '1', titleKey: 'risk_is_whitelisted_title', messageKey: 'risk_is_whitelisted_body', - shouldHide: (info: TokenSecurity) => info.is_whitelisted === undefined, + shouldHide: isUnset('is_whitelisted'), + }, + // true token + { + type: SecurityType.Info, + level: SecurityMessageLevel.Safe, + condition: (info: TokenSecurity) => info.is_true_token === '1', + titleKey: 'risk_is_true_token_title', + messageKey: 'risk_is_true_token_body', + shouldHide: isUnset('is_true_token'), + }, + { + type: SecurityType.Info, + level: SecurityMessageLevel.High, + condition: (info: TokenSecurity) => info.is_true_token === '0', + titleKey: 'risk_not_is_true_token_title', + messageKey: 'risk_not_is_true_token_body', + shouldHide: isUnset('is_true_token'), + }, + // Airdrop scam + { + type: SecurityType.Info, + level: SecurityMessageLevel.Safe, + condition: (info: TokenSecurity) => info.is_airdrop_scam === '0', + titleKey: 'risk_is_airdrop_scam_title', + messageKey: 'risk_is_airdrop_scam_body', + shouldHide: isUnset('is_airdrop_scam'), + }, + { + type: SecurityType.Info, + level: SecurityMessageLevel.High, + condition: (info: TokenSecurity) => info.is_airdrop_scam === '1', + titleKey: 'risk_not_is_airdrop_scam_title', + messageKey: 'risk_not_is_airdrop_scam_body', + shouldHide: isUnset('is_airdrop_scam'), }, ] diff --git a/packages/plugins/GoPlusSecurity/src/locales/en-US.json b/packages/plugins/GoPlusSecurity/src/locales/en-US.json index 737a020e8cfe..d8ad93ff5a73 100644 --- a/packages/plugins/GoPlusSecurity/src/locales/en-US.json +++ b/packages/plugins/GoPlusSecurity/src/locales/en-US.json @@ -75,5 +75,13 @@ "risk_is_whitelisted_title": "Whitelist function", "risk_is_whitelisted_body": "The whitelist function is included. Some addresses may not be able to trade normally (honeypot risk).", "risk_not_is_whitelisted_title": "No whitelist", - "risk_not_is_whitelisted_body": "The whitelist function is not included. If there is a whitelist, some addresses may not be able to trade normally (honeypot risk)." + "risk_not_is_whitelisted_body": "The whitelist function is not included. If there is a whitelist, some addresses may not be able to trade normally (honeypot risk).", + "risk_is_true_token_title": "True Token", + "risk_is_true_token_body": "This token is issued by its declared team. Some scams will create a well-known token with the same name to defraud their users of their assets.", + "risk_not_is_true_token_title": "Fake Token", + "risk_not_is_true_token_body": "This token is not issued by its declared team. Some scams will create a well-known token with the same name to defraud their users of their assets.", + "risk_is_airdrop_scam_title": "Airdrop Scam", + "risk_is_airdrop_scam_body": "You may lose your assets if giving approval to the website of this token.", + "risk_not_is_airdrop_scam_title": "No Airdrop Scam", + "risk_not_is_airdrop_scam_body": "This is not an airdrop scam. Many scams attract users through airdrops." } From c656242f7c390de14e51f1d574637371ba69691a Mon Sep 17 00:00:00 2001 From: Lantt Date: Fri, 8 Apr 2022 18:44:39 +0800 Subject: [PATCH 40/42] fix: should filter asset which not on support chain (#6050) --- .../plugins/EVM/UI/Web3State/getAssetsFn.ts | 45 ++++++++++++------- .../src/plugins/Wallet/services/assets.ts | 1 + 2 files changed, 29 insertions(+), 17 deletions(-) diff --git a/packages/mask/src/plugins/EVM/UI/Web3State/getAssetsFn.ts b/packages/mask/src/plugins/EVM/UI/Web3State/getAssetsFn.ts index f767bbfb913f..d52b42264d73 100644 --- a/packages/mask/src/plugins/EVM/UI/Web3State/getAssetsFn.ts +++ b/packages/mask/src/plugins/EVM/UI/Web3State/getAssetsFn.ts @@ -1,4 +1,11 @@ -import { Pageable, Pagination, TokenType, Web3Plugin } from '@masknet/plugin-infra' +import { + getRegisteredWeb3Networks, + NetworkPluginID, + Pageable, + Pagination, + TokenType, + Web3Plugin, +} from '@masknet/plugin-infra' import BalanceCheckerABI from '@masknet/web3-contracts/abis/BalanceChecker.json' import ERC721ABI from '@masknet/web3-contracts/abis/ERC721.json' import type { ERC721 } from '@masknet/web3-contracts/types/ERC721' @@ -25,7 +32,6 @@ import BigNumber from 'bignumber.js' import { uniqBy } from 'lodash-unified' import Web3 from 'web3' import type { AbiItem } from 'web3-utils' -import { PLUGIN_NETWORKS } from '../../constants' import { makeSortAssertWithoutChainFn } from '../../utils/token' import { createGetLatestBalance } from './createGetLatestBalance' import { createNonFungibleToken } from './createNonFungibleToken' @@ -39,7 +45,10 @@ export const getFungibleAssetsFn = async (address: string, providerType: string, network: Web3Plugin.NetworkDescriptor, pagination?: Pagination) => { const chainId = context.chainId.getCurrentValue() const wallet = context.wallets.getCurrentValue().find((x) => isSameAddress(x.address, address)) - const networks = PLUGIN_NETWORKS + const networks = getRegisteredWeb3Networks().filter( + (x) => NetworkPluginID.PLUGIN_EVM === x.networkSupporterPluginID && x.isMainnet, + ) + const supportedNetworkIds = networks.map((x) => x.chainId) const trustedTokens = uniqBy( context.erc20Tokens .getCurrentValue() @@ -52,22 +61,24 @@ export const getFungibleAssetsFn = ) const { BALANCE_CHECKER_ADDRESS } = getEthereumConstants(chainId) const dataFromProvider = await context.getAssetsList(address, FungibleAssetProvider.DEBANK) - const assetsFromProvider: Web3Plugin.Asset[] = dataFromProvider.map((x) => ({ - id: x.token.address, - chainId: x.token.chainId, - balance: x.balance, - price: x.price, - value: x.value, - logoURI: x.logoURI, - token: { - ...x.token, - type: TokenType.Fungible, - name: x.token.name ?? 'Unknown Token', - symbol: x.token.symbol ?? 'Unknown', + const assetsFromProvider = dataFromProvider + .map>((x) => ({ id: x.token.address, chainId: x.token.chainId, - }, - })) + balance: x.balance, + price: x.price, + value: x.value, + logoURI: x.logoURI, + token: { + ...x.token, + name: x.token.name ?? 'Unknown Token', + symbol: x.token.symbol ?? 'Unknown', + id: x.token.address, + chainId: x.token.chainId, + type: TokenType.Fungible, + }, + })) + .filter((x) => supportedNetworkIds.includes(x.chainId)) const balanceCheckerContract = createContract( web3, diff --git a/packages/mask/src/plugins/Wallet/services/assets.ts b/packages/mask/src/plugins/Wallet/services/assets.ts index 8cb0df11296f..1d1c8c2c3915 100644 --- a/packages/mask/src/plugins/Wallet/services/assets.ts +++ b/packages/mask/src/plugins/Wallet/services/assets.ts @@ -143,6 +143,7 @@ export async function getAssetsList( function formatAssetsFromDebank(data: WalletTokenRecord[], network?: NetworkType) { return data + .filter((x) => getChainIdFromName(x.chain)) .filter((x) => !network || getChainIdFromName(x.chain) === getChainIdFromNetworkType(network)) .filter((x) => x.is_verified) .map((y): Asset => { From 300fea42eb335174d8cf186602db4d2994685e9b Mon Sep 17 00:00:00 2001 From: zhouhanseng Date: Fri, 8 Apr 2022 19:09:53 +0800 Subject: [PATCH 41/42] fix: ui style --- packages/mask/src/plugins/ITO/SNSAdaptor/ITO.tsx | 11 ++++++++--- .../UI/EthereumERC721TokenApprovedBoundary.tsx | 16 ++++++++++++++-- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/packages/mask/src/plugins/ITO/SNSAdaptor/ITO.tsx b/packages/mask/src/plugins/ITO/SNSAdaptor/ITO.tsx index 5d9940820e1a..7c5dd5875a20 100644 --- a/packages/mask/src/plugins/ITO/SNSAdaptor/ITO.tsx +++ b/packages/mask/src/plugins/ITO/SNSAdaptor/ITO.tsx @@ -601,9 +601,14 @@ export function ITO(props: ITO_Props) { const FooterBuyerButton = useMemo( () => ( - +
{(() => { - if (hasLockTime) return FooterBuyerWithLockTimeButton + if (hasLockTime) + return ( + + {FooterBuyerWithLockTimeButton} + + ) if (canWithdraw) { return ( +
), [hasLockTime, canWithdraw], ) diff --git a/packages/mask/src/web3/UI/EthereumERC721TokenApprovedBoundary.tsx b/packages/mask/src/web3/UI/EthereumERC721TokenApprovedBoundary.tsx index f30417c61a95..e10bd3c2760b 100644 --- a/packages/mask/src/web3/UI/EthereumERC721TokenApprovedBoundary.tsx +++ b/packages/mask/src/web3/UI/EthereumERC721TokenApprovedBoundary.tsx @@ -107,7 +107,13 @@ export function EthereumERC721TokenApprovedBoundary(props: EthereumERC712TokenAp loading disabled {...props.ActionButtonProps}> - {t('plugin_wallet_nft_approving_all', { symbol: contractDetailed?.symbol })} + {t('plugin_wallet_nft_approving_all', { + symbol: contractDetailed?.symbol + ? contractDetailed.symbol.toLowerCase() === 'unknown' + ? 'All' + : contractDetailed.symbol + : 'All', + })} ) } else if (validationMessage) { @@ -143,7 +149,13 @@ export function EthereumERC721TokenApprovedBoundary(props: EthereumERC712TokenAp fullWidth onClick={approveCallback} {...props.ActionButtonProps}> - {t('plugin_wallet_approve_all_nft', { symbol: contractDetailed?.symbol })} + {t('plugin_wallet_approve_all_nft', { + symbol: contractDetailed?.symbol + ? contractDetailed.symbol.toLowerCase() === 'unknown' + ? 'All' + : contractDetailed.symbol + : 'All', + })} ) } else if (value === undefined) { From 8eb1da1cca8bb963a86181a4cd6817e8fc6ceb13 Mon Sep 17 00:00:00 2001 From: UncleBill Date: Fri, 8 Apr 2022 22:38:27 +0800 Subject: [PATCH 42/42] fix(tip): adjust size of the badge of WalletIcon (#6044) fix background color in dark mode by the way --- .../mask/src/plugins/NextID/components/Tip/TipDialog.tsx | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/mask/src/plugins/NextID/components/Tip/TipDialog.tsx b/packages/mask/src/plugins/NextID/components/Tip/TipDialog.tsx index 12945c87e5e1..e0e4c8c442e0 100644 --- a/packages/mask/src/plugins/NextID/components/Tip/TipDialog.tsx +++ b/packages/mask/src/plugins/NextID/components/Tip/TipDialog.tsx @@ -36,6 +36,7 @@ import { TipForm } from './TipForm' const useStyles = makeStyles()((theme) => ({ dialog: { width: 600, + backgroundImage: 'none', }, dialogTitle: { height: 60, @@ -257,7 +258,12 @@ export function TipDialog({ open = false, onClose }: TipDialogProps) { const walletChip = account ? (
- +
{walletTitle}