diff --git a/icons/profile.svg b/icons/profile.svg new file mode 100644 index 0000000000..177eea9650 --- /dev/null +++ b/icons/profile.svg @@ -0,0 +1,3 @@ + + + diff --git a/lib/mixpanel/utils.ts b/lib/mixpanel/utils.ts index f2dff64716..fae1b8e327 100644 --- a/lib/mixpanel/utils.ts +++ b/lib/mixpanel/utils.ts @@ -61,6 +61,7 @@ Type extends EventTypes.VERIFY_TOKEN ? { 'Action': 'Form opened' | 'Submit'; } : Type extends EventTypes.WALLET_CONNECT ? { + 'Source': 'Header' | 'Smart contracts'; 'Status': 'Started' | 'Connected'; } : Type extends EventTypes.CONTRACT_INTERACTION ? { diff --git a/package.json b/package.json index 7d96b46026..c68d889774 100644 --- a/package.json +++ b/package.json @@ -60,6 +60,7 @@ "chakra-react-select": "^4.4.3", "crypto-js": "^4.1.1", "d3": "^7.6.1", + "dappscout-iframe": "^0.1.0", "dayjs": "^1.11.5", "dom-to-image": "^2.6.0", "framer-motion": "^6.5.1", diff --git a/pages/_app.tsx b/pages/_app.tsx index b9d77d5c53..14a70d043f 100644 --- a/pages/_app.tsx +++ b/pages/_app.tsx @@ -17,6 +17,7 @@ import theme from 'theme'; import AppErrorBoundary from 'ui/shared/AppError/AppErrorBoundary'; import GoogleAnalytics from 'ui/shared/GoogleAnalytics'; import Layout from 'ui/shared/layout/Layout'; +import Web3ModalProvider from 'ui/shared/Web3ModalProvider'; import 'lib/setLocale'; @@ -52,17 +53,19 @@ function MyApp({ Component, pageProps }: AppPropsWithLayout) { { ...ERROR_SCREEN_STYLES } onError={ handleError } > - - - - - { getLayout() } - - - - - - + + + + + + { getLayout() } + + + + + + + ); diff --git a/pages/apps/[id].tsx b/pages/apps/[id].tsx index 108643409e..f99be74026 100644 --- a/pages/apps/[id].tsx +++ b/pages/apps/[id].tsx @@ -6,6 +6,8 @@ import type { NextPageWithLayout } from 'nextjs/types'; import type { Props } from 'nextjs/getServerSideProps'; import PageNextJs from 'nextjs/PageNextJs'; +import LayoutApp from 'ui/shared/layout/LayoutApp'; + const MarketplaceApp = dynamic(() => import('ui/pages/MarketplaceApp'), { ssr: false }); const Page: NextPageWithLayout = (props: Props) => { @@ -16,6 +18,14 @@ const Page: NextPageWithLayout = (props: Props) => { ); }; +Page.getLayout = function getLayout(page: React.ReactElement) { + return ( + + { page } + + ); +}; + export default Page; export { marketplace as getServerSideProps } from 'nextjs/getServerSideProps'; diff --git a/pages/apps/index.tsx b/pages/apps/index.tsx index 7184417759..5b95867329 100644 --- a/pages/apps/index.tsx +++ b/pages/apps/index.tsx @@ -12,7 +12,7 @@ const Page: NextPage = () => { return ( <> - + diff --git a/ui/address/contract/ContractConnectWallet.tsx b/ui/address/contract/ContractConnectWallet.tsx index eab09c0eaf..d3118bcc66 100644 --- a/ui/address/contract/ContractConnectWallet.tsx +++ b/ui/address/contract/ContractConnectWallet.tsx @@ -17,11 +17,11 @@ const ContractConnectWallet = () => { setIsModalOpening(true); await open(); setIsModalOpening(false); - mixpanel.logEvent(mixpanel.EventTypes.WALLET_CONNECT, { Status: 'Started' }); + mixpanel.logEvent(mixpanel.EventTypes.WALLET_CONNECT, { Source: 'Smart contracts', Status: 'Started' }); }, [ open ]); const handleAccountConnected = React.useCallback(({ isReconnected }: { isReconnected: boolean }) => { - !isReconnected && mixpanel.logEvent(mixpanel.EventTypes.WALLET_CONNECT, { Status: 'Connected' }); + !isReconnected && mixpanel.logEvent(mixpanel.EventTypes.WALLET_CONNECT, { Source: 'Smart contracts', Status: 'Connected' }); }, []); const handleDisconnect = React.useCallback(() => { diff --git a/ui/marketplace/MarketplaceAppCard.tsx b/ui/marketplace/MarketplaceAppCard.tsx index 29e50ce30d..0c6ba28dc8 100644 --- a/ui/marketplace/MarketplaceAppCard.tsx +++ b/ui/marketplace/MarketplaceAppCard.tsx @@ -15,6 +15,7 @@ interface Props extends MarketplaceAppPreview { isFavorite: boolean; onFavoriteClick: (id: string, isFavorite: boolean) => void; isLoading: boolean; + showDisclaimer: (id: string) => void; } const MarketplaceAppCard = ({ @@ -30,9 +31,18 @@ const MarketplaceAppCard = ({ isFavorite, onFavoriteClick, isLoading, + showDisclaimer, }: Props) => { const categoriesLabel = categories.join(', '); + const handleClick = useCallback((event: MouseEvent) => { + const isShown = window.localStorage.getItem('marketplace-disclaimer-shown'); + if (!isShown) { + event.preventDefault(); + showDisclaimer(id); + } + }, [ showDisclaimer, id ]); + const handleInfoClick = useCallback((event: MouseEvent) => { event.preventDefault(); onInfoClick(id); @@ -100,6 +110,7 @@ const MarketplaceAppCard = ({ url={ url } external={ external } title={ title } + onClick={ handleClick } /> diff --git a/ui/marketplace/MarketplaceAppCardLink.tsx b/ui/marketplace/MarketplaceAppCardLink.tsx index 63589c7923..4fdf338e2e 100644 --- a/ui/marketplace/MarketplaceAppCardLink.tsx +++ b/ui/marketplace/MarketplaceAppCardLink.tsx @@ -1,22 +1,24 @@ import { LinkOverlay } from '@chakra-ui/react'; import NextLink from 'next/link'; import React from 'react'; +import type { MouseEvent } from 'react'; type Props = { id: string; url: string; external?: boolean; title: string; + onClick?: (event: MouseEvent) => void; } -const MarketplaceAppCardLink = ({ url, external, id, title }: Props) => { +const MarketplaceAppCardLink = ({ url, external, id, title, onClick }: Props) => { return external ? ( { title } ) : ( - + { title } diff --git a/ui/marketplace/MarketplaceDisclaimerModal.tsx b/ui/marketplace/MarketplaceDisclaimerModal.tsx new file mode 100644 index 0000000000..a1cffbb320 --- /dev/null +++ b/ui/marketplace/MarketplaceDisclaimerModal.tsx @@ -0,0 +1,81 @@ +import { Heading, Modal, ModalBody, ModalContent, ModalFooter, ModalHeader, ModalOverlay, Text, Button, useColorModeValue } from '@chakra-ui/react'; +import NextLink from 'next/link'; +import React from 'react'; + +import useIsMobile from 'lib/hooks/useIsMobile'; + +type Props = { + isOpen: boolean; + onClose: () => void; + appId: string; +} + +const MarketplaceDisclaimerModal = ({ isOpen, onClose, appId }: Props) => { + + const isMobile = useIsMobile(); + + const handleContinueClick = React.useCallback(() => { + window.localStorage.setItem('marketplace-disclaimer-shown', 'true'); + }, [ ]); + + return ( + + + + + + + Disclaimer + + + + + + You are now accessing a third-party app. Blockscout does not own, control, maintain, or audit 3rd party apps,{ ' ' } + and is not liable for any losses associated with these interactions. Please do so at your own risk. +

+ By clicking continue, you agree that you understand the risks and have read the Disclaimer. +
+
+ + + + + + + +
+
+ ); +}; + +export default MarketplaceDisclaimerModal; diff --git a/ui/marketplace/MarketplaceList.tsx b/ui/marketplace/MarketplaceList.tsx index 6660fe42b2..98abb23dd6 100644 --- a/ui/marketplace/MarketplaceList.tsx +++ b/ui/marketplace/MarketplaceList.tsx @@ -14,9 +14,10 @@ type Props = { favoriteApps: Array; onFavoriteClick: (id: string, isFavorite: boolean) => void; isLoading: boolean; + showDisclaimer: (id: string) => void; } -const MarketplaceList = ({ apps, onAppClick, favoriteApps, onFavoriteClick, isLoading }: Props) => { +const MarketplaceList = ({ apps, onAppClick, favoriteApps, onFavoriteClick, isLoading, showDisclaimer }: Props) => { return apps.length > 0 ? ( )) } diff --git a/ui/marketplace/useMarketplace.tsx b/ui/marketplace/useMarketplace.tsx index 204baefa1b..7c8c86b9ea 100644 --- a/ui/marketplace/useMarketplace.tsx +++ b/ui/marketplace/useMarketplace.tsx @@ -29,6 +29,8 @@ export default function useMarketplace() { const [ selectedCategoryId, setSelectedCategoryId ] = React.useState(MarketplaceCategory.ALL); const [ filterQuery, setFilterQuery ] = React.useState(defaultFilterQuery); const [ favoriteApps, setFavoriteApps ] = React.useState>([]); + const [ isAppInfoModalOpen, setIsAppInfoModalOpen ] = React.useState(false); + const [ isDisclaimerModalOpen, setIsDisclaimerModalOpen ] = React.useState(false); const handleFavoriteClick = React.useCallback((id: string, isFavorite: boolean) => { const favoriteApps = getFavoriteApps(); @@ -46,10 +48,20 @@ export default function useMarketplace() { const showAppInfo = React.useCallback((id: string) => { setSelectedAppId(id); + setIsAppInfoModalOpen(true); + }, []); + + const showDisclaimer = React.useCallback((id: string) => { + setSelectedAppId(id); + setIsDisclaimerModalOpen(true); }, []); const debouncedFilterQuery = useDebounce(filterQuery, 500); - const clearSelectedAppId = React.useCallback(() => setSelectedAppId(null), []); + const clearSelectedAppId = React.useCallback(() => { + setSelectedAppId(null); + setIsAppInfoModalOpen(false); + setIsDisclaimerModalOpen(false); + }, []); const handleCategoryChange = React.useCallback((newCategory: string) => { setSelectedCategoryId(newCategory); @@ -104,6 +116,9 @@ export default function useMarketplace() { clearSelectedAppId, favoriteApps, onFavoriteClick: handleFavoriteClick, + isAppInfoModalOpen, + isDisclaimerModalOpen, + showDisclaimer, }), [ selectedCategoryId, categories, @@ -118,5 +133,8 @@ export default function useMarketplace() { isPlaceholderData, showAppInfo, debouncedFilterQuery, + isAppInfoModalOpen, + isDisclaimerModalOpen, + showDisclaimer, ]); } diff --git a/ui/marketplace/useMarketplaceWallet.tsx b/ui/marketplace/useMarketplaceWallet.tsx new file mode 100644 index 0000000000..17370ea6bd --- /dev/null +++ b/ui/marketplace/useMarketplaceWallet.tsx @@ -0,0 +1,64 @@ +import type { TypedData } from 'abitype'; +import { useCallback } from 'react'; +import type { Account, SignTypedDataParameters } from 'viem'; +import { useAccount, useSendTransaction, useSwitchNetwork, useNetwork, useSignMessage, useSignTypedData } from 'wagmi'; + +import config from 'configs/app'; + +type SendTransactionArgs = { + chainId?: number; + mode?: 'prepared'; + to: string; +}; + +export type SignTypedDataArgs< + TTypedData extends + | TypedData + | { + [key: string]: unknown; + } = TypedData, + TPrimaryType extends string = string, +> = SignTypedDataParameters; + +export default function useMarketplaceWallet() { + const { address } = useAccount(); + const { chain } = useNetwork(); + const { sendTransactionAsync } = useSendTransaction(); + const { signMessageAsync } = useSignMessage(); + const { signTypedDataAsync } = useSignTypedData(); + const { switchNetworkAsync } = useSwitchNetwork({ chainId: Number(config.chain.id) }); + + const switchNetwork = useCallback(async() => { + if (Number(config.chain.id) !== chain?.id) { + await switchNetworkAsync?.(); + } + }, [ chain, switchNetworkAsync ]); + + const sendTransaction = useCallback(async(transaction: SendTransactionArgs) => { + await switchNetwork(); + const tx = await sendTransactionAsync(transaction); + return tx.hash; + }, [ sendTransactionAsync, switchNetwork ]); + + const signMessage = useCallback(async(message: string) => { + await switchNetwork(); + const signature = await signMessageAsync({ message }); + return signature; + }, [ signMessageAsync, switchNetwork ]); + + const signTypedData = useCallback(async(typedData: SignTypedDataArgs) => { + await switchNetwork(); + if (typedData.domain) { + typedData.domain.chainId = Number(typedData.domain.chainId); + } + const signature = await signTypedDataAsync(typedData); + return signature; + }, [ signTypedDataAsync, switchNetwork ]); + + return { + address, + sendTransaction, + signMessage, + signTypedData, + }; +} diff --git a/ui/pages/Home.tsx b/ui/pages/Home.tsx index 0ca90465fe..14d9cc2684 100644 --- a/ui/pages/Home.tsx +++ b/ui/pages/Home.tsx @@ -10,6 +10,7 @@ import Transactions from 'ui/home/Transactions'; import AdBanner from 'ui/shared/ad/AdBanner'; import ProfileMenuDesktop from 'ui/snippets/profileMenu/ProfileMenuDesktop'; import SearchBar from 'ui/snippets/searchBar/SearchBar'; +import WalletMenuDesktop from 'ui/snippets/walletMenu/WalletMenuDesktop'; const Home = () => { return ( @@ -22,7 +23,7 @@ const Home = () => { minW={{ base: 'unset', lg: '900px' }} data-label="hero plate" > - + { > { config.chain.name } explorer - - { config.features.account.isEnabled && } + + { config.features.account.isEnabled && } + { config.features.blockchainInteraction.isEnabled && } diff --git a/ui/pages/Marketplace.tsx b/ui/pages/Marketplace.tsx index 499f72fe66..4314b20db0 100644 --- a/ui/pages/Marketplace.tsx +++ b/ui/pages/Marketplace.tsx @@ -5,6 +5,7 @@ import config from 'configs/app'; import PlusIcon from 'icons/plus.svg'; import MarketplaceAppModal from 'ui/marketplace/MarketplaceAppModal'; import MarketplaceCategoriesMenu from 'ui/marketplace/MarketplaceCategoriesMenu'; +import MarketplaceDisclaimerModal from 'ui/marketplace/MarketplaceDisclaimerModal'; import MarketplaceList from 'ui/marketplace/MarketplaceList'; import FilterInput from 'ui/shared/filters/FilterInput'; @@ -27,6 +28,9 @@ const Marketplace = () => { clearSelectedAppId, favoriteApps, onFavoriteClick, + isAppInfoModalOpen, + isDisclaimerModalOpen, + showDisclaimer, } = useMarketplace(); if (isError) { @@ -68,9 +72,10 @@ const Marketplace = () => { favoriteApps={ favoriteApps } onFavoriteClick={ onFavoriteClick } isLoading={ isPlaceholderData } + showDisclaimer={ showDisclaimer } /> - { selectedApp && ( + { (selectedApp && isAppInfoModalOpen) && ( { /> ) } + { (selectedApp && isDisclaimerModalOpen) && ( + + ) } + { - const ref = useRef(null); - - const apiFetch = useApiFetch(); - const appProps = useAppContext(); - const router = useRouter(); - const id = getQueryParamString(router.query.id); - - const { isPending, isError, error, data } = useQuery, MarketplaceAppOverview>({ - queryKey: [ 'marketplace-apps', id ], - queryFn: async() => { - const result = await apiFetch, unknown>(configUrl, undefined, { resource: 'marketplace-apps' }); - if (!Array.isArray(result)) { - throw result; - } - - const item = result.find((app: MarketplaceAppOverview) => app.id === id); - if (!item) { - throw { status: 404 }; - } +type Props = { + address: string | undefined; + data: MarketplaceAppOverview | undefined; + isPending: boolean; +}; - return item; - }, - enabled: feature.isEnabled, - }); +const MarketplaceAppContent = ({ address, data, isPending }: Props) => { + const { iframeRef, isReady } = useDappscoutIframe(); + const [ iframeKey, setIframeKey ] = useState(0); const [ isFrameLoading, setIsFrameLoading ] = useState(isPending); const { colorMode } = useColorMode(); + useEffect(() => { + setIframeKey((key) => key + 1); + }, [ address ]); + const handleIframeLoad = useCallback(() => { setIsFrameLoading(false); }, []); @@ -72,9 +61,61 @@ const MarketplaceApp = () => { blockscoutNetworkRpc: config.chain.rpcUrl, }; - ref?.current?.contentWindow?.postMessage(message, data.url); + iframeRef?.current?.contentWindow?.postMessage(message, data.url); } - }, [ isFrameLoading, data, colorMode, ref ]); + }, [ isFrameLoading, data, colorMode, iframeRef ]); + + return ( +
+ { (isFrameLoading) && ( + + ) } + + { (data && isReady) && ( + + ) } +
+ ); +}; + +const MarketplaceApp = () => { + const { address, sendTransaction, signMessage, signTypedData } = useMarketplaceWallet(); + + const apiFetch = useApiFetch(); + const router = useRouter(); + const id = getQueryParamString(router.query.id); + + const { isPending, isError, error, data } = useQuery, MarketplaceAppOverview>({ + queryKey: [ 'marketplace-apps', id ], + queryFn: async() => { + const result = await apiFetch, unknown>(configUrl, undefined, { resource: 'marketplace-apps' }); + if (!Array.isArray(result)) { + throw result; + } + const item = result.find((app: MarketplaceAppOverview) => app.id === id); + if (!item) { + throw { status: 404 }; + } + + return item; + }, + enabled: feature.isEnabled, + }); useEffect(() => { if (data) { @@ -89,46 +130,17 @@ const MarketplaceApp = () => { throw new Error('Unable to load app', { cause: error }); } - const backLink = React.useMemo(() => { - const hasGoBackLink = appProps.referrer.includes('/apps'); - - if (!hasGoBackLink) { - return; - } - - return { - label: 'Back to marketplace', - url: appProps.referrer, - }; - }, [ appProps.referrer ]); - return ( - <> - { !isPending && } -
- { (isFrameLoading) && ( - - ) } - - { data && ( - - ) } -
- + + + ); }; diff --git a/ui/pages/__screenshots__/Home.pw.tsx_dark-color-mode_default-view---default-dark-mode-1.png b/ui/pages/__screenshots__/Home.pw.tsx_dark-color-mode_default-view---default-dark-mode-1.png index d6c15ecd89..d12829e733 100644 Binary files a/ui/pages/__screenshots__/Home.pw.tsx_dark-color-mode_default-view---default-dark-mode-1.png and b/ui/pages/__screenshots__/Home.pw.tsx_dark-color-mode_default-view---default-dark-mode-1.png differ diff --git a/ui/pages/__screenshots__/Home.pw.tsx_default_custom-hero-plate-background-default-view-1.png b/ui/pages/__screenshots__/Home.pw.tsx_default_custom-hero-plate-background-default-view-1.png index 6446e988dc..1851dc3744 100644 Binary files a/ui/pages/__screenshots__/Home.pw.tsx_default_custom-hero-plate-background-default-view-1.png and b/ui/pages/__screenshots__/Home.pw.tsx_default_custom-hero-plate-background-default-view-1.png differ diff --git a/ui/pages/__screenshots__/Home.pw.tsx_default_default-view-screen-xl-1.png b/ui/pages/__screenshots__/Home.pw.tsx_default_default-view-screen-xl-1.png index c1633fcc41..fe31926fdd 100644 Binary files a/ui/pages/__screenshots__/Home.pw.tsx_default_default-view-screen-xl-1.png and b/ui/pages/__screenshots__/Home.pw.tsx_default_default-view-screen-xl-1.png differ diff --git a/ui/shared/UserAvatar.tsx b/ui/shared/UserAvatar.tsx index 0f2c2d2685..644c273023 100644 --- a/ui/shared/UserAvatar.tsx +++ b/ui/shared/UserAvatar.tsx @@ -1,10 +1,10 @@ -import { SkeletonCircle, Image } from '@chakra-ui/react'; +import { SkeletonCircle, Image, Icon } from '@chakra-ui/react'; import React from 'react'; +import profileIcon from 'icons/profile.svg'; import { useAppContext } from 'lib/contexts/app'; import * as cookies from 'lib/cookies'; import useFetchProfileInfo from 'lib/hooks/useFetchProfileInfo'; -import IdenticonGithub from 'ui/shared/IdenticonGithub'; interface Props { size: number; @@ -34,7 +34,7 @@ const UserAvatar = ({ size }: Props) => { boxSize={ `${ size }px` } borderRadius="full" overflow="hidden" - fallback={ isImageLoadError || !data?.avatar ? : undefined } + fallback={ isImageLoadError || !data?.avatar ? : undefined } onError={ handleImageLoadError } /> ); diff --git a/ui/shared/Web3ModalProvider.tsx b/ui/shared/Web3ModalProvider.tsx index 3a7a48579d..bb4cf19cf8 100644 --- a/ui/shared/Web3ModalProvider.tsx +++ b/ui/shared/Web3ModalProvider.tsx @@ -75,7 +75,7 @@ const Web3ModalProvider = ({ children, fallback }: Props) => { const web3ModalTheme = useColorModeValue('light', 'dark'); if (!wagmiConfig || !ethereumClient || !feature.isEnabled) { - return typeof fallback === 'function' ? fallback() : (fallback || null); + return typeof fallback === 'function' ? fallback() : (fallback || <>{ children }); // eslint-disable-line react/jsx-no-useless-fragment } return ( diff --git a/ui/shared/layout/LayoutApp.tsx b/ui/shared/layout/LayoutApp.tsx new file mode 100644 index 0000000000..469ef3b536 --- /dev/null +++ b/ui/shared/layout/LayoutApp.tsx @@ -0,0 +1,35 @@ +import React from 'react'; + +import type { Props } from './types'; + +import AppErrorBoundary from 'ui/shared/AppError/AppErrorBoundary'; +import HeaderAlert from 'ui/snippets/header/HeaderAlert'; +import HeaderDesktop from 'ui/snippets/header/HeaderDesktop'; +import HeaderMobile from 'ui/snippets/header/HeaderMobile'; + +import * as Layout from './components'; + +const LayoutDefault = ({ children }: Props) => { + return ( + + + + + + + + + { children } + + + + + + + ); +}; + +export default LayoutDefault; diff --git a/ui/shared/layout/__screenshots__/Layout.pw.tsx_default_base-view-mobile-1.png b/ui/shared/layout/__screenshots__/Layout.pw.tsx_default_base-view-mobile-1.png index b49b5b8f9d..bdf253f4a1 100644 Binary files a/ui/shared/layout/__screenshots__/Layout.pw.tsx_default_base-view-mobile-1.png and b/ui/shared/layout/__screenshots__/Layout.pw.tsx_default_base-view-mobile-1.png differ diff --git a/ui/shared/layout/__screenshots__/Layout.pw.tsx_mobile_base-view-mobile-1.png b/ui/shared/layout/__screenshots__/Layout.pw.tsx_mobile_base-view-mobile-1.png index e59315df1f..f98ebbef6b 100644 Binary files a/ui/shared/layout/__screenshots__/Layout.pw.tsx_mobile_base-view-mobile-1.png and b/ui/shared/layout/__screenshots__/Layout.pw.tsx_mobile_base-view-mobile-1.png differ diff --git a/ui/shared/layout/__screenshots__/LayoutError.pw.tsx_mobile_base-view-mobile-1.png b/ui/shared/layout/__screenshots__/LayoutError.pw.tsx_mobile_base-view-mobile-1.png index 102fdcd463..67165f334b 100644 Binary files a/ui/shared/layout/__screenshots__/LayoutError.pw.tsx_mobile_base-view-mobile-1.png and b/ui/shared/layout/__screenshots__/LayoutError.pw.tsx_mobile_base-view-mobile-1.png differ diff --git a/ui/shared/layout/__screenshots__/LayoutHome.pw.tsx_mobile_base-view-mobile-1.png b/ui/shared/layout/__screenshots__/LayoutHome.pw.tsx_mobile_base-view-mobile-1.png index ea7255000a..c2757cbc13 100644 Binary files a/ui/shared/layout/__screenshots__/LayoutHome.pw.tsx_mobile_base-view-mobile-1.png and b/ui/shared/layout/__screenshots__/LayoutHome.pw.tsx_mobile_base-view-mobile-1.png differ diff --git a/ui/shared/layout/components/Content.tsx b/ui/shared/layout/components/Content.tsx index 85f8d497ec..4f6ddf23c1 100644 --- a/ui/shared/layout/components/Content.tsx +++ b/ui/shared/layout/components/Content.tsx @@ -1,16 +1,17 @@ -import { Box } from '@chakra-ui/react'; +import { Box, chakra } from '@chakra-ui/react'; import React from 'react'; interface Props { + className?: string; children: React.ReactNode; } -const Content = ({ children }: Props) => { +const Content = ({ children, className }: Props) => { return ( - + { children } ); }; -export default React.memo(Content); +export default React.memo(chakra(Content)); diff --git a/ui/snippets/header/Burger.tsx b/ui/snippets/header/Burger.tsx index 08f655b915..9b41bd6335 100644 --- a/ui/snippets/header/Burger.tsx +++ b/ui/snippets/header/Burger.tsx @@ -10,7 +10,11 @@ import NetworkMenuButton from 'ui/snippets/networkMenu/NetworkMenuButton'; import NetworkMenuContentMobile from 'ui/snippets/networkMenu/NetworkMenuContentMobile'; import useNetworkMenu from 'ui/snippets/networkMenu/useNetworkMenu'; -const Burger = () => { +interface Props { + isMarketplaceAppPage?: boolean; +} + +const Burger = ({ isMarketplaceAppPage }: Props) => { const iconColor = useColorModeValue('gray.600', 'white'); const { isOpen, onOpen, onClose } = useDisclosure(); const networkMenu = useNetworkMenu(); @@ -26,7 +30,7 @@ const Burger = () => { return ( <> - + {
{ networkMenu.isOpen ? : - + } diff --git a/ui/snippets/header/HeaderDesktop.tsx b/ui/snippets/header/HeaderDesktop.tsx index bb74577036..5da9566f03 100644 --- a/ui/snippets/header/HeaderDesktop.tsx +++ b/ui/snippets/header/HeaderDesktop.tsx @@ -2,14 +2,19 @@ import { HStack, Box } from '@chakra-ui/react'; import React from 'react'; import config from 'configs/app'; +import NetworkLogo from 'ui/snippets/networkMenu/NetworkLogo'; import ProfileMenuDesktop from 'ui/snippets/profileMenu/ProfileMenuDesktop'; import SearchBar from 'ui/snippets/searchBar/SearchBar'; +import WalletMenuDesktop from 'ui/snippets/walletMenu/WalletMenuDesktop'; + +import Burger from './Burger'; type Props = { renderSearchBar?: () => React.ReactNode; + isMarketplaceAppPage?: boolean; } -const HeaderDesktop = ({ renderSearchBar }: Props) => { +const HeaderDesktop = ({ renderSearchBar, isMarketplaceAppPage }: Props) => { const searchBar = renderSearchBar ? renderSearchBar() : ; @@ -22,10 +27,19 @@ const HeaderDesktop = ({ renderSearchBar }: Props) => { justifyContent="center" gap={ 12 } > + { isMarketplaceAppPage && ( + + + + + ) } { searchBar } - { config.features.account.isEnabled && } + + { config.features.account.isEnabled && } + { config.features.blockchainInteraction.isEnabled && } + ); }; diff --git a/ui/snippets/header/HeaderMobile.tsx b/ui/snippets/header/HeaderMobile.tsx index 4da61d7305..9901d8b9f9 100644 --- a/ui/snippets/header/HeaderMobile.tsx +++ b/ui/snippets/header/HeaderMobile.tsx @@ -7,6 +7,7 @@ import { useScrollDirection } from 'lib/contexts/scrollDirection'; import NetworkLogo from 'ui/snippets/networkMenu/NetworkLogo'; import ProfileMenuMobile from 'ui/snippets/profileMenu/ProfileMenuMobile'; import SearchBar from 'ui/snippets/searchBar/SearchBar'; +import WalletMenuMobile from 'ui/snippets/walletMenu/WalletMenuMobile'; import Burger from './Burger'; @@ -47,7 +48,10 @@ const HeaderMobile = ({ isHomePage, renderSearchBar }: Props) => { > - { config.features.account.isEnabled ? : } + + { config.features.account.isEnabled ? : } + { config.features.blockchainInteraction.isEnabled && } + { !isHomePage && searchBar } diff --git a/ui/snippets/header/__screenshots__/Header.pw.tsx_default_dark-mode-mobile-1.png b/ui/snippets/header/__screenshots__/Header.pw.tsx_default_dark-mode-mobile-1.png new file mode 100644 index 0000000000..30293cf379 Binary files /dev/null and b/ui/snippets/header/__screenshots__/Header.pw.tsx_default_dark-mode-mobile-1.png differ diff --git a/ui/snippets/header/__screenshots__/Header.pw.tsx_default_no-auth-mobile-1.png b/ui/snippets/header/__screenshots__/Header.pw.tsx_default_no-auth-mobile-1.png new file mode 100644 index 0000000000..2530860b2c Binary files /dev/null and b/ui/snippets/header/__screenshots__/Header.pw.tsx_default_no-auth-mobile-1.png differ diff --git a/ui/snippets/header/__screenshots__/Header.pw.tsx_mobile_dark-mode-mobile-1.png b/ui/snippets/header/__screenshots__/Header.pw.tsx_mobile_dark-mode-mobile-1.png new file mode 100644 index 0000000000..f4a2a016ad Binary files /dev/null and b/ui/snippets/header/__screenshots__/Header.pw.tsx_mobile_dark-mode-mobile-1.png differ diff --git a/ui/snippets/header/__screenshots__/Header.pw.tsx_mobile_no-auth-mobile-1.png b/ui/snippets/header/__screenshots__/Header.pw.tsx_mobile_no-auth-mobile-1.png new file mode 100644 index 0000000000..d771a74802 Binary files /dev/null and b/ui/snippets/header/__screenshots__/Header.pw.tsx_mobile_no-auth-mobile-1.png differ diff --git a/ui/snippets/header/__screenshots__/HeaderDesktop.pw.tsx_dark-color-mode_default-view-dark-mode-1.png b/ui/snippets/header/__screenshots__/HeaderDesktop.pw.tsx_dark-color-mode_default-view-dark-mode-1.png index bc42b56cce..20aa839385 100644 Binary files a/ui/snippets/header/__screenshots__/HeaderDesktop.pw.tsx_dark-color-mode_default-view-dark-mode-1.png and b/ui/snippets/header/__screenshots__/HeaderDesktop.pw.tsx_dark-color-mode_default-view-dark-mode-1.png differ diff --git a/ui/snippets/header/__screenshots__/HeaderDesktop.pw.tsx_default_default-view-dark-mode-1.png b/ui/snippets/header/__screenshots__/HeaderDesktop.pw.tsx_default_default-view-dark-mode-1.png index c913661089..d143733147 100644 Binary files a/ui/snippets/header/__screenshots__/HeaderDesktop.pw.tsx_default_default-view-dark-mode-1.png and b/ui/snippets/header/__screenshots__/HeaderDesktop.pw.tsx_default_default-view-dark-mode-1.png differ diff --git a/ui/snippets/header/__screenshots__/HeaderMobile.pw.tsx_dark-color-mode_default-view-dark-mode-1.png b/ui/snippets/header/__screenshots__/HeaderMobile.pw.tsx_dark-color-mode_default-view-dark-mode-1.png index d59bf1a960..01dba03498 100644 Binary files a/ui/snippets/header/__screenshots__/HeaderMobile.pw.tsx_dark-color-mode_default-view-dark-mode-1.png and b/ui/snippets/header/__screenshots__/HeaderMobile.pw.tsx_dark-color-mode_default-view-dark-mode-1.png differ diff --git a/ui/snippets/header/__screenshots__/HeaderMobile.pw.tsx_default_default-view-dark-mode-1.png b/ui/snippets/header/__screenshots__/HeaderMobile.pw.tsx_default_default-view-dark-mode-1.png index bd92fc60b7..803a3f79ec 100644 Binary files a/ui/snippets/header/__screenshots__/HeaderMobile.pw.tsx_default_default-view-dark-mode-1.png and b/ui/snippets/header/__screenshots__/HeaderMobile.pw.tsx_default_default-view-dark-mode-1.png differ diff --git a/ui/snippets/navigation/NavLinkGroupMobile.tsx b/ui/snippets/navigation/NavLinkGroupMobile.tsx index 091a982973..60604cc124 100644 --- a/ui/snippets/navigation/NavLinkGroupMobile.tsx +++ b/ui/snippets/navigation/NavLinkGroupMobile.tsx @@ -17,10 +17,11 @@ import useNavLinkStyleProps from './useNavLinkStyleProps'; type Props = { item: NavGroupItem; onClick: () => void; + isExpanded?: boolean; } -const NavLinkGroup = ({ item, onClick }: Props) => { - const styleProps = useNavLinkStyleProps({ isActive: item.isActive }); +const NavLinkGroup = ({ item, onClick, isExpanded }: Props) => { + const styleProps = useNavLinkStyleProps({ isActive: item.isActive, isExpanded }); return ( diff --git a/ui/snippets/navigation/NavigationMobile.tsx b/ui/snippets/navigation/NavigationMobile.tsx index a55365793d..7b0c4d354b 100644 --- a/ui/snippets/navigation/NavigationMobile.tsx +++ b/ui/snippets/navigation/NavigationMobile.tsx @@ -11,9 +11,10 @@ import NavLinkGroupMobile from './NavLinkGroupMobile'; interface Props { onNavLinkClick?: () => void; + isMarketplaceAppPage?: boolean; } -const NavigationMobile = ({ onNavLinkClick }: Props) => { +const NavigationMobile = ({ onNavLinkClick, isMarketplaceAppPage }: Props) => { const { mainNavItems, accountNavItems } = useNavItems(); const [ openedGroupIndex, setOpenedGroupIndex ] = React.useState(-1); @@ -38,6 +39,8 @@ const NavigationMobile = ({ onNavLinkClick }: Props) => { const openedItem = mainNavItems[openedGroupIndex]; + const isCollapsed = isMarketplaceAppPage ? false : undefined; + return ( { > { mainNavItems.map((item, index) => { if (isGroupItem(item)) { - return ; + return ; } else { - return ; + return ; } }) } @@ -77,7 +80,7 @@ const NavigationMobile = ({ onNavLinkClick }: Props) => { borderColor="divider" > - { accountNavItems.map((item) => ) } + { accountNavItems.map((item) => ) } ) } @@ -113,10 +116,10 @@ const NavigationMobile = ({ onNavLinkClick }: Props) => { borderColor: 'divider', }} > - { item.map(subItem => ) } + { item.map(subItem => ) } ) : - , + , ) } diff --git a/ui/snippets/profileMenu/ProfileMenuDesktop.pw.tsx b/ui/snippets/profileMenu/ProfileMenuDesktop.pw.tsx index 1fa67bf456..858c26f729 100644 --- a/ui/snippets/profileMenu/ProfileMenuDesktop.pw.tsx +++ b/ui/snippets/profileMenu/ProfileMenuDesktop.pw.tsx @@ -23,7 +23,7 @@ test('no auth', async({ mount, page }) => { { hooksConfig }, ); - await component.locator('.identicon').click(); + await component.locator('a').click(); expect(page.url()).toBe(`${ app.url }/auth/auth0?path=%2F`); }); diff --git a/ui/snippets/profileMenu/ProfileMenuDesktop.tsx b/ui/snippets/profileMenu/ProfileMenuDesktop.tsx index 8d5dea0a70..9592758040 100644 --- a/ui/snippets/profileMenu/ProfileMenuDesktop.tsx +++ b/ui/snippets/profileMenu/ProfileMenuDesktop.tsx @@ -1,5 +1,5 @@ -import type { ButtonProps } from '@chakra-ui/react'; -import { Popover, PopoverContent, PopoverBody, PopoverTrigger, Button } from '@chakra-ui/react'; +import type { IconButtonProps } from '@chakra-ui/react'; +import { Popover, PopoverContent, PopoverBody, PopoverTrigger, IconButton, Tooltip, Box } from '@chakra-ui/react'; import React from 'react'; import useFetchProfileInfo from 'lib/hooks/useFetchProfileInfo'; @@ -8,9 +8,16 @@ import * as mixpanel from 'lib/mixpanel/index'; import UserAvatar from 'ui/shared/UserAvatar'; import ProfileMenuContent from 'ui/snippets/profileMenu/ProfileMenuContent'; -const ProfileMenuDesktop = () => { +import useMenuButtonColors from '../useMenuButtonColors'; + +type Props = { + isHomePage?: boolean; +}; + +const ProfileMenuDesktop = ({ isHomePage }: Props) => { const { data, error, isPending } = useFetchProfileInfo(); const loginUrl = useLoginUrl(); + const { themedBackground, themedBorderColor, themedColor } = useMenuButtonColors(); const [ hasMenu, setHasMenu ] = React.useState(false); React.useEffect(() => { @@ -27,7 +34,7 @@ const ProfileMenuDesktop = () => { ); }, []); - const buttonProps: Partial = (() => { + const iconButtonProps: Partial = (() => { if (hasMenu || !loginUrl) { return {}; } @@ -39,19 +46,53 @@ const ProfileMenuDesktop = () => { }; })(); + const variant = React.useMemo(() => { + if (hasMenu) { + return 'subtle'; + } + return isHomePage ? 'solid' : 'outline'; + }, [ hasMenu, isHomePage ]); + + let iconButtonStyles: Partial = {}; + if (hasMenu) { + iconButtonStyles = { + bg: isHomePage ? 'blue.50' : themedBackground, + }; + } else if (isHomePage) { + iconButtonStyles = { + color: 'white', + }; + } else { + iconButtonStyles = { + borderColor: themedBorderColor, + color: themedColor, + }; + } + return ( - - - + Sign in to My Account to add tags,
create watchlists, access API keys and more } + textAlign="center" + padding={ 2 } + isDisabled={ hasMenu } + openDelay={ 300 } + > + + + } + variant={ variant } + colorScheme="blue" + boxSize="40px" + flexShrink={ 0 } + { ...iconButtonProps } + { ...iconButtonStyles } + /> + + +
{ hasMenu && ( diff --git a/ui/snippets/profileMenu/ProfileMenuMobile.pw.tsx b/ui/snippets/profileMenu/ProfileMenuMobile.pw.tsx index 627c998353..b5d3fcc373 100644 --- a/ui/snippets/profileMenu/ProfileMenuMobile.pw.tsx +++ b/ui/snippets/profileMenu/ProfileMenuMobile.pw.tsx @@ -23,7 +23,7 @@ test('no auth', async({ mount, page }) => { { hooksConfig }, ); - await component.locator('.identicon').click(); + await component.locator('a').click(); expect(page.url()).toBe(`${ app.url }/auth/auth0?path=%2F`); }); diff --git a/ui/snippets/profileMenu/ProfileMenuMobile.tsx b/ui/snippets/profileMenu/ProfileMenuMobile.tsx index bce294a20c..0a1b97eda6 100644 --- a/ui/snippets/profileMenu/ProfileMenuMobile.tsx +++ b/ui/snippets/profileMenu/ProfileMenuMobile.tsx @@ -1,5 +1,5 @@ -import { Box, Drawer, DrawerOverlay, DrawerContent, DrawerBody, useDisclosure, Button } from '@chakra-ui/react'; -import type { ButtonProps } from '@chakra-ui/react'; +import { Drawer, DrawerOverlay, DrawerContent, DrawerBody, useDisclosure, IconButton } from '@chakra-ui/react'; +import type { IconButtonProps } from '@chakra-ui/react'; import React from 'react'; import useFetchProfileInfo from 'lib/hooks/useFetchProfileInfo'; @@ -8,11 +8,13 @@ import * as mixpanel from 'lib/mixpanel/index'; import UserAvatar from 'ui/shared/UserAvatar'; import ProfileMenuContent from 'ui/snippets/profileMenu/ProfileMenuContent'; +import useMenuButtonColors from '../useMenuButtonColors'; + const ProfileMenuMobile = () => { const { isOpen, onOpen, onClose } = useDisclosure(); - const { data, error, isPending } = useFetchProfileInfo(); const loginUrl = useLoginUrl(); + const { themedBackground, themedBorderColor, themedColor } = useMenuButtonColors(); const [ hasMenu, setHasMenu ] = React.useState(false); const handleSignInClick = React.useCallback(() => { @@ -29,7 +31,7 @@ const ProfileMenuMobile = () => { } }, [ data, error?.status, isPending ]); - const buttonProps: Partial = (() => { + const iconButtonProps: Partial = (() => { if (hasMenu || !loginUrl) { return {}; } @@ -43,17 +45,19 @@ const ProfileMenuMobile = () => { return ( <> - - - + } + variant={ data?.avatar ? 'subtle' : 'outline' } + colorScheme="gray" + boxSize="40px" + flexShrink={ 0 } + bg={ data?.avatar ? themedBackground : undefined } + color={ themedColor } + borderColor={ !data?.avatar ? themedBorderColor : undefined } + onClick={ hasMenu ? onOpen : undefined } + { ...iconButtonProps } + /> { hasMenu && ( void; +}; + +const WalletMenuContent = ({ address, disconnect }: Props) => ( + + + My wallet + + + Your wallet is used to interact with apps and contracts in the explorer. + + + + +); + +export default WalletMenuContent; diff --git a/ui/snippets/walletMenu/WalletMenuDesktop.tsx b/ui/snippets/walletMenu/WalletMenuDesktop.tsx new file mode 100644 index 0000000000..6bc3629d12 --- /dev/null +++ b/ui/snippets/walletMenu/WalletMenuDesktop.tsx @@ -0,0 +1,94 @@ +import type { ButtonProps } from '@chakra-ui/react'; +import { Popover, PopoverContent, PopoverBody, PopoverTrigger, Button, Box, useBoolean } from '@chakra-ui/react'; +import React from 'react'; + +import AddressIdenticon from 'ui/shared/entities/address/AddressIdenticon'; +import HashStringShorten from 'ui/shared/HashStringShorten'; +import useWallet from 'ui/snippets/walletMenu/useWallet'; +import WalletMenuContent from 'ui/snippets/walletMenu/WalletMenuContent'; + +import useMenuButtonColors from '../useMenuButtonColors'; +import WalletTooltip from './WalletTooltip'; + +type Props = { + isHomePage?: boolean; +}; + +const WalletMenuDesktop = ({ isHomePage }: Props) => { + const { isWalletConnected, address, connect, disconnect, isModalOpening, isModalOpen } = useWallet(); + const { themedBackground, themedBorderColor, themedColor } = useMenuButtonColors(); + const [ isPopoverOpen, setIsPopoverOpen ] = useBoolean(false); + + const variant = React.useMemo(() => { + if (isWalletConnected) { + return 'subtle'; + } + return isHomePage ? 'solid' : 'outline'; + }, [ isWalletConnected, isHomePage ]); + + let buttonStyles: Partial = {}; + if (isWalletConnected) { + buttonStyles = { + bg: isHomePage ? 'blue.50' : themedBackground, + color: isHomePage ? 'blackAlpha.800' : themedColor, + _hover: { + color: isHomePage ? 'blackAlpha.800' : themedColor, + }, + }; + } else if (isHomePage) { + buttonStyles = { + color: 'white', + }; + } else { + buttonStyles = { + borderColor: themedBorderColor, + color: themedColor, + }; + } + + return ( + + + + + + + + + { isWalletConnected && ( + + + + + + ) } + + ); +}; + +export default WalletMenuDesktop; diff --git a/ui/snippets/walletMenu/WalletMenuMobile.tsx b/ui/snippets/walletMenu/WalletMenuMobile.tsx new file mode 100644 index 0000000000..57b0145cc4 --- /dev/null +++ b/ui/snippets/walletMenu/WalletMenuMobile.tsx @@ -0,0 +1,56 @@ +import { Drawer, DrawerOverlay, DrawerContent, DrawerBody, useDisclosure, IconButton, Icon } from '@chakra-ui/react'; +import React from 'react'; + +import walletIcon from 'icons/wallet.svg'; +import AddressIdenticon from 'ui/shared/entities/address/AddressIdenticon'; +import useWallet from 'ui/snippets/walletMenu/useWallet'; +import WalletMenuContent from 'ui/snippets/walletMenu/WalletMenuContent'; + +import useMenuButtonColors from '../useMenuButtonColors'; +import WalletTooltip from './WalletTooltip'; + +const WalletMenuMobile = () => { + const { isOpen, onOpen, onClose } = useDisclosure(); + const { isWalletConnected, address, connect, disconnect, isModalOpening, isModalOpen } = useWallet(); + const { themedBackground, themedBorderColor, themedColor } = useMenuButtonColors(); + + return ( + <> + + : + + } + variant={ isWalletConnected ? 'subtle' : 'outline' } + colorScheme="gray" + boxSize="40px" + flexShrink={ 0 } + bg={ isWalletConnected ? themedBackground : undefined } + color={ themedColor } + borderColor={ !isWalletConnected ? themedBorderColor : undefined } + onClick={ isWalletConnected ? onOpen : connect } + isLoading={ isModalOpening || isModalOpen } + /> + + { isWalletConnected && ( + + + + + + + + + ) } + + ); +}; + +export default WalletMenuMobile; diff --git a/ui/snippets/walletMenu/WalletTooltip.tsx b/ui/snippets/walletMenu/WalletTooltip.tsx new file mode 100644 index 0000000000..7a769fe374 --- /dev/null +++ b/ui/snippets/walletMenu/WalletTooltip.tsx @@ -0,0 +1,38 @@ +import { Tooltip, useBoolean } from '@chakra-ui/react'; +import React from 'react'; + +type Props = { + children: React.ReactNode; + isDisabled?: boolean; + isMobile?: boolean; +}; + +const WalletTooltip = ({ children, isDisabled, isMobile }: Props) => { + const [ isTooltipShown, setIsTooltipShown ] = useBoolean(false); + + React.useEffect(() => { + const key = `wallet-connect-tooltip-shown-${ isMobile ? 'mobile' : 'desktop' }`; + const wasShown = window.localStorage.getItem(key); + if (!wasShown) { + setIsTooltipShown.on(); + window.localStorage.setItem(key, 'true'); + } + }, [ setIsTooltipShown, isMobile ]); + + return ( + Your wallet is used to interact with
apps and contracts in the explorer } + textAlign="center" + padding={ 2 } + isDisabled={ isDisabled } + openDelay={ 300 } + isOpen={ isTooltipShown || (isMobile ? false : undefined) } + onClose={ setIsTooltipShown.off } + display={ isMobile ? { base: 'flex', lg: 'none' } : { base: 'none', lg: 'flex' } } + > + { children } +
+ ); +}; + +export default WalletTooltip; diff --git a/ui/snippets/walletMenu/useWallet.tsx b/ui/snippets/walletMenu/useWallet.tsx new file mode 100644 index 0000000000..fe8d93f719 --- /dev/null +++ b/ui/snippets/walletMenu/useWallet.tsx @@ -0,0 +1,44 @@ +import { useWeb3Modal } from '@web3modal/react'; +import React from 'react'; +import { useAccount, useDisconnect } from 'wagmi'; + +import * as mixpanel from 'lib/mixpanel/index'; + +export default function useWallet() { + const { open, isOpen } = useWeb3Modal(); + const { disconnect } = useDisconnect(); + const [ isModalOpening, setIsModalOpening ] = React.useState(false); + const [ isClientLoaded, setIsClientLoaded ] = React.useState(false); + + React.useEffect(() => { + setIsClientLoaded(true); + }, []); + + const handleConnect = React.useCallback(async() => { + setIsModalOpening(true); + await open(); + setIsModalOpening(false); + mixpanel.logEvent(mixpanel.EventTypes.WALLET_CONNECT, { Source: 'Header', Status: 'Started' }); + }, [ open ]); + + const handleAccountConnected = React.useCallback(({ isReconnected }: { isReconnected: boolean }) => { + !isReconnected && mixpanel.logEvent(mixpanel.EventTypes.WALLET_CONNECT, { Source: 'Header', Status: 'Connected' }); + }, []); + + const handleDisconnect = React.useCallback(() => { + disconnect(); + }, [ disconnect ]); + + const { address, isDisconnected } = useAccount({ onConnect: handleAccountConnected }); + + const isWalletConnected = isClientLoaded && !isDisconnected && address !== undefined; + + return { + isWalletConnected, + address: address || '', + connect: handleConnect, + disconnect: handleDisconnect, + isModalOpening, + isModalOpen: isOpen, + }; +} diff --git a/yarn.lock b/yarn.lock index d6fc51bce7..eddd6fa3f2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2429,6 +2429,348 @@ ethereum-cryptography "^2.0.0" micro-ftch "^0.3.1" +"@ethersproject/abi@5.7.0", "@ethersproject/abi@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/abi/-/abi-5.7.0.tgz#b3f3e045bbbeed1af3947335c247ad625a44e449" + integrity sha512-351ktp42TiRcYB3H1OP8yajPeAQstMW/yCFokj/AthP9bLHzQFPlOrxOcwYEDkUAICmOHljvN4K39OMTMUa9RA== + dependencies: + "@ethersproject/address" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/constants" "^5.7.0" + "@ethersproject/hash" "^5.7.0" + "@ethersproject/keccak256" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/strings" "^5.7.0" + +"@ethersproject/abstract-provider@5.7.0", "@ethersproject/abstract-provider@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/abstract-provider/-/abstract-provider-5.7.0.tgz#b0a8550f88b6bf9d51f90e4795d48294630cb9ef" + integrity sha512-R41c9UkchKCpAqStMYUpdunjo3pkEvZC3FAwZn5S5MGbXoMQOHIdHItezTETxAO5bevtMApSyEhn9+CHcDsWBw== + dependencies: + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/networks" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/transactions" "^5.7.0" + "@ethersproject/web" "^5.7.0" + +"@ethersproject/abstract-signer@5.7.0", "@ethersproject/abstract-signer@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/abstract-signer/-/abstract-signer-5.7.0.tgz#13f4f32117868452191a4649723cb086d2b596b2" + integrity sha512-a16V8bq1/Cz+TGCkE2OPMTOUDLS3grCpdjoJCYNnVBbdYEMSgKrU0+B90s8b6H+ByYTBZN7a3g76jdIJi7UfKQ== + dependencies: + "@ethersproject/abstract-provider" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + +"@ethersproject/address@5.7.0", "@ethersproject/address@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/address/-/address-5.7.0.tgz#19b56c4d74a3b0a46bfdbb6cfcc0a153fc697f37" + integrity sha512-9wYhYt7aghVGo758POM5nqcOMaE168Q6aRLJZwUmiqSrAungkG74gSSeKEIR7ukixesdRZGPgVqme6vmxs1fkA== + dependencies: + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/keccak256" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/rlp" "^5.7.0" + +"@ethersproject/base64@5.7.0", "@ethersproject/base64@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/base64/-/base64-5.7.0.tgz#ac4ee92aa36c1628173e221d0d01f53692059e1c" + integrity sha512-Dr8tcHt2mEbsZr/mwTPIQAf3Ai0Bks/7gTw9dSqk1mQvhW3XvRlmDJr/4n+wg1JmCl16NZue17CDh8xb/vZ0sQ== + dependencies: + "@ethersproject/bytes" "^5.7.0" + +"@ethersproject/basex@5.7.0", "@ethersproject/basex@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/basex/-/basex-5.7.0.tgz#97034dc7e8938a8ca943ab20f8a5e492ece4020b" + integrity sha512-ywlh43GwZLv2Voc2gQVTKBoVQ1mti3d8HK5aMxsfu/nRDnMmNqaSJ3r3n85HBByT8OpoY96SXM1FogC533T4zw== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + +"@ethersproject/bignumber@5.7.0", "@ethersproject/bignumber@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/bignumber/-/bignumber-5.7.0.tgz#e2f03837f268ba655ffba03a57853e18a18dc9c2" + integrity sha512-n1CAdIHRWjSucQO3MC1zPSVgV/6dy/fjL9pMrPP9peL+QxEg9wOsVqwD4+818B6LUEtaXzVHQiuivzRoxPxUGw== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + bn.js "^5.2.1" + +"@ethersproject/bytes@5.7.0", "@ethersproject/bytes@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/bytes/-/bytes-5.7.0.tgz#a00f6ea8d7e7534d6d87f47188af1148d71f155d" + integrity sha512-nsbxwgFXWh9NyYWo+U8atvmMsSdKJprTcICAkvbBffT75qDocbuggBU0SJiVK2MuTrp0q+xvLkTnGMPK1+uA9A== + dependencies: + "@ethersproject/logger" "^5.7.0" + +"@ethersproject/constants@5.7.0", "@ethersproject/constants@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/constants/-/constants-5.7.0.tgz#df80a9705a7e08984161f09014ea012d1c75295e" + integrity sha512-DHI+y5dBNvkpYUMiRQyxRBYBefZkJfo70VUkUAsRjcPs47muV9evftfZ0PJVCXYbAiCgght0DtcF9srFQmIgWA== + dependencies: + "@ethersproject/bignumber" "^5.7.0" + +"@ethersproject/contracts@5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/contracts/-/contracts-5.7.0.tgz#c305e775abd07e48aa590e1a877ed5c316f8bd1e" + integrity sha512-5GJbzEU3X+d33CdfPhcyS+z8MzsTrBGk/sc+G+59+tPa9yFkl6HQ9D6L0QMgNTA9q8dT0XKxxkyp883XsQvbbg== + dependencies: + "@ethersproject/abi" "^5.7.0" + "@ethersproject/abstract-provider" "^5.7.0" + "@ethersproject/abstract-signer" "^5.7.0" + "@ethersproject/address" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/constants" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/transactions" "^5.7.0" + +"@ethersproject/hash@5.7.0", "@ethersproject/hash@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/hash/-/hash-5.7.0.tgz#eb7aca84a588508369562e16e514b539ba5240a7" + integrity sha512-qX5WrQfnah1EFnO5zJv1v46a8HW0+E5xuBBDTwMFZLuVTx0tbU2kkx15NqdjxecrLGatQN9FGQKpb1FKdHCt+g== + dependencies: + "@ethersproject/abstract-signer" "^5.7.0" + "@ethersproject/address" "^5.7.0" + "@ethersproject/base64" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/keccak256" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/strings" "^5.7.0" + +"@ethersproject/hdnode@5.7.0", "@ethersproject/hdnode@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/hdnode/-/hdnode-5.7.0.tgz#e627ddc6b466bc77aebf1a6b9e47405ca5aef9cf" + integrity sha512-OmyYo9EENBPPf4ERhR7oj6uAtUAhYGqOnIS+jE5pTXvdKBS99ikzq1E7Iv0ZQZ5V36Lqx1qZLeak0Ra16qpeOg== + dependencies: + "@ethersproject/abstract-signer" "^5.7.0" + "@ethersproject/basex" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/pbkdf2" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/sha2" "^5.7.0" + "@ethersproject/signing-key" "^5.7.0" + "@ethersproject/strings" "^5.7.0" + "@ethersproject/transactions" "^5.7.0" + "@ethersproject/wordlists" "^5.7.0" + +"@ethersproject/json-wallets@5.7.0", "@ethersproject/json-wallets@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/json-wallets/-/json-wallets-5.7.0.tgz#5e3355287b548c32b368d91014919ebebddd5360" + integrity sha512-8oee5Xgu6+RKgJTkvEMl2wDgSPSAQ9MB/3JYjFV9jlKvcYHUXZC+cQp0njgmxdHkYWn8s6/IqIZYm0YWCjO/0g== + dependencies: + "@ethersproject/abstract-signer" "^5.7.0" + "@ethersproject/address" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/hdnode" "^5.7.0" + "@ethersproject/keccak256" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/pbkdf2" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/random" "^5.7.0" + "@ethersproject/strings" "^5.7.0" + "@ethersproject/transactions" "^5.7.0" + aes-js "3.0.0" + scrypt-js "3.0.1" + +"@ethersproject/keccak256@5.7.0", "@ethersproject/keccak256@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/keccak256/-/keccak256-5.7.0.tgz#3186350c6e1cd6aba7940384ec7d6d9db01f335a" + integrity sha512-2UcPboeL/iW+pSg6vZ6ydF8tCnv3Iu/8tUmLLzWWGzxWKFFqOBQFLo6uLUv6BDrLgCDfN28RJ/wtByx+jZ4KBg== + dependencies: + "@ethersproject/bytes" "^5.7.0" + js-sha3 "0.8.0" + +"@ethersproject/logger@5.7.0", "@ethersproject/logger@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/logger/-/logger-5.7.0.tgz#6ce9ae168e74fecf287be17062b590852c311892" + integrity sha512-0odtFdXu/XHtjQXJYA3u9G0G8btm0ND5Cu8M7i5vhEcE8/HmF4Lbdqanwyv4uQTr2tx6b7fQRmgLrsnpQlmnig== + +"@ethersproject/networks@5.7.1", "@ethersproject/networks@^5.7.0": + version "5.7.1" + resolved "https://registry.yarnpkg.com/@ethersproject/networks/-/networks-5.7.1.tgz#118e1a981d757d45ccea6bb58d9fd3d9db14ead6" + integrity sha512-n/MufjFYv3yFcUyfhnXotyDlNdFb7onmkSy8aQERi2PjNcnWQ66xXxa3XlS8nCcA8aJKJjIIMNJTC7tu80GwpQ== + dependencies: + "@ethersproject/logger" "^5.7.0" + +"@ethersproject/pbkdf2@5.7.0", "@ethersproject/pbkdf2@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/pbkdf2/-/pbkdf2-5.7.0.tgz#d2267d0a1f6e123f3771007338c47cccd83d3102" + integrity sha512-oR/dBRZR6GTyaofd86DehG72hY6NpAjhabkhxgr3X2FpJtJuodEl2auADWBZfhDHgVCbu3/H/Ocq2uC6dpNjjw== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/sha2" "^5.7.0" + +"@ethersproject/properties@5.7.0", "@ethersproject/properties@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/properties/-/properties-5.7.0.tgz#a6e12cb0439b878aaf470f1902a176033067ed30" + integrity sha512-J87jy8suntrAkIZtecpxEPxY//szqr1mlBaYlQ0r4RCaiD2hjheqF9s1LVE8vVuJCXisjIP+JgtK/Do54ej4Sw== + dependencies: + "@ethersproject/logger" "^5.7.0" + +"@ethersproject/providers@5.7.2": + version "5.7.2" + resolved "https://registry.yarnpkg.com/@ethersproject/providers/-/providers-5.7.2.tgz#f8b1a4f275d7ce58cf0a2eec222269a08beb18cb" + integrity sha512-g34EWZ1WWAVgr4aptGlVBF8mhl3VWjv+8hoAnzStu8Ah22VHBsuGzP17eb6xDVRzw895G4W7vvx60lFFur/1Rg== + dependencies: + "@ethersproject/abstract-provider" "^5.7.0" + "@ethersproject/abstract-signer" "^5.7.0" + "@ethersproject/address" "^5.7.0" + "@ethersproject/base64" "^5.7.0" + "@ethersproject/basex" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/constants" "^5.7.0" + "@ethersproject/hash" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/networks" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/random" "^5.7.0" + "@ethersproject/rlp" "^5.7.0" + "@ethersproject/sha2" "^5.7.0" + "@ethersproject/strings" "^5.7.0" + "@ethersproject/transactions" "^5.7.0" + "@ethersproject/web" "^5.7.0" + bech32 "1.1.4" + ws "7.4.6" + +"@ethersproject/random@5.7.0", "@ethersproject/random@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/random/-/random-5.7.0.tgz#af19dcbc2484aae078bb03656ec05df66253280c" + integrity sha512-19WjScqRA8IIeWclFme75VMXSBvi4e6InrUNuaR4s5pTF2qNhcGdCUwdxUVGtDDqC00sDLCO93jPQoDUH4HVmQ== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + +"@ethersproject/rlp@5.7.0", "@ethersproject/rlp@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/rlp/-/rlp-5.7.0.tgz#de39e4d5918b9d74d46de93af80b7685a9c21304" + integrity sha512-rBxzX2vK8mVF7b0Tol44t5Tb8gomOHkj5guL+HhzQ1yBh/ydjGnpw6at+X6Iw0Kp3OzzzkcKp8N9r0W4kYSs9w== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + +"@ethersproject/sha2@5.7.0", "@ethersproject/sha2@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/sha2/-/sha2-5.7.0.tgz#9a5f7a7824ef784f7f7680984e593a800480c9fb" + integrity sha512-gKlH42riwb3KYp0reLsFTokByAKoJdgFCwI+CCiX/k+Jm2mbNs6oOaCjYQSlI1+XBVejwH2KrmCbMAT/GnRDQw== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + hash.js "1.1.7" + +"@ethersproject/signing-key@5.7.0", "@ethersproject/signing-key@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/signing-key/-/signing-key-5.7.0.tgz#06b2df39411b00bc57c7c09b01d1e41cf1b16ab3" + integrity sha512-MZdy2nL3wO0u7gkB4nA/pEf8lu1TlFswPNmy8AiYkfKTdO6eXBJyUdmHO/ehm/htHw9K/qF8ujnTyUAD+Ry54Q== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + bn.js "^5.2.1" + elliptic "6.5.4" + hash.js "1.1.7" + +"@ethersproject/solidity@5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/solidity/-/solidity-5.7.0.tgz#5e9c911d8a2acce2a5ebb48a5e2e0af20b631cb8" + integrity sha512-HmabMd2Dt/raavyaGukF4XxizWKhKQ24DoLtdNbBmNKUOPqwjsKQSdV9GQtj9CBEea9DlzETlVER1gYeXXBGaA== + dependencies: + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/keccak256" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/sha2" "^5.7.0" + "@ethersproject/strings" "^5.7.0" + +"@ethersproject/strings@5.7.0", "@ethersproject/strings@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/strings/-/strings-5.7.0.tgz#54c9d2a7c57ae8f1205c88a9d3a56471e14d5ed2" + integrity sha512-/9nu+lj0YswRNSH0NXYqrh8775XNyEdUQAuf3f+SmOrnVewcJ5SBNAjF7lpgehKi4abvNNXyf+HX86czCdJ8Mg== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/constants" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + +"@ethersproject/transactions@5.7.0", "@ethersproject/transactions@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/transactions/-/transactions-5.7.0.tgz#91318fc24063e057885a6af13fdb703e1f993d3b" + integrity sha512-kmcNicCp1lp8qanMTC3RIikGgoJ80ztTyvtsFvCYpSCfkjhD0jZ2LOrnbcuxuToLIUYYf+4XwD1rP+B/erDIhQ== + dependencies: + "@ethersproject/address" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/constants" "^5.7.0" + "@ethersproject/keccak256" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/rlp" "^5.7.0" + "@ethersproject/signing-key" "^5.7.0" + +"@ethersproject/units@5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/units/-/units-5.7.0.tgz#637b563d7e14f42deeee39245275d477aae1d8b1" + integrity sha512-pD3xLMy3SJu9kG5xDGI7+xhTEmGXlEqXU4OfNapmfnxLVY4EMSSRp7j1k7eezutBPH7RBN/7QPnwR7hzNlEFeg== + dependencies: + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/constants" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + +"@ethersproject/wallet@5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/wallet/-/wallet-5.7.0.tgz#4e5d0790d96fe21d61d38fb40324e6c7ef350b2d" + integrity sha512-MhmXlJXEJFBFVKrDLB4ZdDzxcBxQ3rLyCkhNqVu3CDYvR97E+8r01UgrI+TI99Le+aYm/in/0vp86guJuM7FCA== + dependencies: + "@ethersproject/abstract-provider" "^5.7.0" + "@ethersproject/abstract-signer" "^5.7.0" + "@ethersproject/address" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/hash" "^5.7.0" + "@ethersproject/hdnode" "^5.7.0" + "@ethersproject/json-wallets" "^5.7.0" + "@ethersproject/keccak256" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/random" "^5.7.0" + "@ethersproject/signing-key" "^5.7.0" + "@ethersproject/transactions" "^5.7.0" + "@ethersproject/wordlists" "^5.7.0" + +"@ethersproject/web@5.7.1", "@ethersproject/web@^5.7.0": + version "5.7.1" + resolved "https://registry.yarnpkg.com/@ethersproject/web/-/web-5.7.1.tgz#de1f285b373149bee5928f4eb7bcb87ee5fbb4ae" + integrity sha512-Gueu8lSvyjBWL4cYsWsjh6MtMwM0+H4HvqFPZfB6dV8ctbP9zFAO73VG1cMWae0FLPCtz0peKPpZY8/ugJJX2w== + dependencies: + "@ethersproject/base64" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/strings" "^5.7.0" + +"@ethersproject/wordlists@5.7.0", "@ethersproject/wordlists@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/wordlists/-/wordlists-5.7.0.tgz#8fb2c07185d68c3e09eb3bfd6e779ba2774627f5" + integrity sha512-S2TFNJNfHWVHNE6cNDjbVlZ6MgE17MIxMbMg2zv3wn+3XSJGosL1m9ZVv3GXCf/2ymSsQ+hRI5IzoMJTG6aoVA== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/hash" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/strings" "^5.7.0" + "@fastify/busboy@^2.0.0": version "2.0.0" resolved "https://registry.yarnpkg.com/@fastify/busboy/-/busboy-2.0.0.tgz#f22824caff3ae506b18207bad4126dbc6ccdb6b8" @@ -6944,6 +7286,11 @@ acorn@^8.8.0: resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.0.tgz#88c0187620435c7f6015803f5539dae05a9dbea8" integrity sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w== +aes-js@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/aes-js/-/aes-js-3.0.0.tgz#e21df10ad6c2053295bcbb8dab40b09dbea87e4d" + integrity sha512-H7wUZRn8WpTq9jocdxQ2c8x2sKo9ZVmzfRE13GiNJXfp7NcKYEdvl3vspKjXox6RIG2VtaRe4JFvxG4rqp2Zuw== + aes-js@^3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/aes-js/-/aes-js-3.1.2.tgz#db9aabde85d5caabbfc0d4f2a4446960f627146a" @@ -7330,6 +7677,11 @@ base64-js@^1.3.1, base64-js@^1.5.1: resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== +bech32@1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/bech32/-/bech32-1.1.4.tgz#e38c9f37bf179b8eb16ae3a772b40c356d4832e9" + integrity sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ== + bigint-buffer@^1.1.5: version "1.1.5" resolved "https://registry.yarnpkg.com/bigint-buffer/-/bigint-buffer-1.1.5.tgz#d038f31c8e4534c1f8d0015209bf34b4fa6dd442" @@ -7378,7 +7730,12 @@ blo@^1.1.1: resolved "https://registry.yarnpkg.com/blo/-/blo-1.1.1.tgz#ed781c5c516fba484ec8ec86105dc27f6c553209" integrity sha512-1uGZInlRD4X1WQP2G1QjDGwGZ8HdGgFKqnzyRdA2TYYc0MOQCmCi37RTQ8oJuI0UF6DYFKXHwV/t1kZkO/fTaA== -bn.js@^5.0.0, bn.js@^5.1.1, bn.js@^5.2.0: +bn.js@^4.11.9: + version "4.12.0" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.12.0.tgz#775b3f278efbb9718eec7361f483fb36fbbfea88" + integrity sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA== + +bn.js@^5.0.0, bn.js@^5.1.1, bn.js@^5.2.0, bn.js@^5.2.1: version "5.2.1" resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.1.tgz#0bc527a6a0d18d0aa8d5b0538ce4a77dccfa7b70" integrity sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ== @@ -7419,6 +7776,11 @@ braces@^3.0.2, braces@~3.0.2: dependencies: fill-range "^7.0.1" +brorand@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" + integrity sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w== + browserslist@^4.21.3, browserslist@^4.21.4: version "4.21.4" resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.21.4.tgz#e7496bbc67b9e39dd0f98565feccdcb0d4ff6987" @@ -8220,6 +8582,15 @@ damerau-levenshtein@^1.0.8: resolved "https://registry.yarnpkg.com/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz#b43d286ccbd36bc5b2f7ed41caf2d0aba1f8a6e7" integrity sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA== +dappscout-iframe@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/dappscout-iframe/-/dappscout-iframe-0.1.0.tgz#c971d8a8aa4fb3d64ca357700d3ac809dcdecb0d" + integrity sha512-nL65Uuv2+r2ujELyBtw+VL6PYkUtleCvKi2XaeMiroZz6tieeUw338PEOc6cZaIfwXk59rFwNR0FZki2HnOrIA== + dependencies: + ethers "^5.7.2" + react "^18.2.0" + react-dom "^18.2.0" + data-uri-to-buffer@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/data-uri-to-buffer/-/data-uri-to-buffer-4.0.0.tgz#b5db46aea50f6176428ac05b73be39a57701a64b" @@ -8534,6 +8905,19 @@ electron-to-chromium@^1.4.251: resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.276.tgz#17837b19dafcc43aba885c4689358b298c19b520" integrity sha512-EpuHPqu8YhonqLBXHoU6hDJCD98FCe6KDoet3/gY1qsQ6usjJoHqBH2YIVs8FXaAtHwVL8Uqa/fsYao/vq9VWQ== +elliptic@6.5.4: + version "6.5.4" + resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.4.tgz#da37cebd31e79a1367e941b592ed1fbebd58abbb" + integrity sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ== + dependencies: + bn.js "^4.11.9" + brorand "^1.1.0" + hash.js "^1.0.0" + hmac-drbg "^1.0.1" + inherits "^2.0.4" + minimalistic-assert "^1.0.1" + minimalistic-crypto-utils "^1.0.1" + emittery@^0.13.1: version "0.13.1" resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.13.1.tgz#c04b8c3457490e0847ae51fced3af52d338e3dad" @@ -9143,6 +9527,42 @@ ethereum-cryptography@^2.0.0: "@scure/bip32" "1.3.1" "@scure/bip39" "1.2.1" +ethers@^5.7.2: + version "5.7.2" + resolved "https://registry.yarnpkg.com/ethers/-/ethers-5.7.2.tgz#3a7deeabbb8c030d4126b24f84e525466145872e" + integrity sha512-wswUsmWo1aOK8rR7DIKiWSw9DbLWe6x98Jrn8wcTflTVvaXhAMaB5zGAXy0GYQEQp9iO1iSHWVyARQm11zUtyg== + dependencies: + "@ethersproject/abi" "5.7.0" + "@ethersproject/abstract-provider" "5.7.0" + "@ethersproject/abstract-signer" "5.7.0" + "@ethersproject/address" "5.7.0" + "@ethersproject/base64" "5.7.0" + "@ethersproject/basex" "5.7.0" + "@ethersproject/bignumber" "5.7.0" + "@ethersproject/bytes" "5.7.0" + "@ethersproject/constants" "5.7.0" + "@ethersproject/contracts" "5.7.0" + "@ethersproject/hash" "5.7.0" + "@ethersproject/hdnode" "5.7.0" + "@ethersproject/json-wallets" "5.7.0" + "@ethersproject/keccak256" "5.7.0" + "@ethersproject/logger" "5.7.0" + "@ethersproject/networks" "5.7.1" + "@ethersproject/pbkdf2" "5.7.0" + "@ethersproject/properties" "5.7.0" + "@ethersproject/providers" "5.7.2" + "@ethersproject/random" "5.7.0" + "@ethersproject/rlp" "5.7.0" + "@ethersproject/sha2" "5.7.0" + "@ethersproject/signing-key" "5.7.0" + "@ethersproject/solidity" "5.7.0" + "@ethersproject/strings" "5.7.0" + "@ethersproject/transactions" "5.7.0" + "@ethersproject/units" "5.7.0" + "@ethersproject/wallet" "5.7.0" + "@ethersproject/web" "5.7.1" + "@ethersproject/wordlists" "5.7.0" + event-target-shim@^5.0.0: version "5.0.1" resolved "https://registry.yarnpkg.com/event-target-shim/-/event-target-shim-5.0.1.tgz#5d4d3ebdf9583d63a5333ce2deb7480ab2b05789" @@ -9821,7 +10241,7 @@ has@^1.0.3: dependencies: function-bind "^1.1.1" -hash.js@^1.1.7: +hash.js@1.1.7, hash.js@^1.0.0, hash.js@^1.0.3, hash.js@^1.1.7: version "1.1.7" resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.7.tgz#0babca538e8d4ee4a0f8988d68866537a003cf42" integrity sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA== @@ -9880,6 +10300,15 @@ highlight.js@^10.4.1, highlight.js@~10.7.0: resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-10.7.3.tgz#697272e3991356e40c3cac566a74eef681756531" integrity sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A== +hmac-drbg@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" + integrity sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg== + dependencies: + hash.js "^1.0.3" + minimalistic-assert "^1.0.0" + minimalistic-crypto-utils "^1.0.1" + hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.1, hoist-non-react-statics@^3.3.2: version "3.3.2" resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45" @@ -10850,6 +11279,11 @@ js-sdsl@^4.1.4: resolved "https://registry.yarnpkg.com/js-sdsl/-/js-sdsl-4.2.0.tgz#278e98b7bea589b8baaf048c20aeb19eb7ad09d0" integrity sha512-dyBIzQBDkCqCu+0upx25Y2jGdbTGxE9fshMsCdK0ViOongpV+n5tXRcZY9v7CaVQ79AGS9KA1KHtojxiM7aXSQ== +js-sha3@0.8.0: + version "0.8.0" + resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.8.0.tgz#b9b7a5da73afad7dedd0f8c463954cbde6818840" + integrity sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q== + "js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" @@ -11370,11 +11804,16 @@ minim@~0.23.8: dependencies: lodash "^4.15.0" -minimalistic-assert@^1.0.1: +minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== +minimalistic-crypto-utils@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" + integrity sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg== + minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" @@ -12617,7 +13056,7 @@ react-device-detect@^2.2.3: dependencies: ua-parser-js "^1.0.33" -react-dom@18.2.0: +react-dom@18.2.0, react-dom@^18.2.0: version "18.2.0" resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.2.0.tgz#22aaf38708db2674ed9ada224ca4aa708d821e3d" integrity sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g== @@ -12806,7 +13245,7 @@ react@17.0.2: loose-envify "^1.1.0" object-assign "^4.1.1" -react@18.2.0: +react@18.2.0, react@^18.2.0: version "18.2.0" resolved "https://registry.yarnpkg.com/react/-/react-18.2.0.tgz#555bd98592883255fa00de14f1151a917b5d77d5" integrity sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ== @@ -13235,6 +13674,11 @@ scheduler@^0.23.0: dependencies: loose-envify "^1.1.0" +scrypt-js@3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/scrypt-js/-/scrypt-js-3.0.1.tgz#d314a57c2aef69d1ad98a138a21fe9eafa9ee312" + integrity sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA== + scslre@^0.1.6: version "0.1.6" resolved "https://registry.yarnpkg.com/scslre/-/scslre-0.1.6.tgz#71a2832e4bf3a9254973a04fbed90aec94f75757" @@ -14594,6 +15038,11 @@ write-file-atomic@^4.0.1: imurmurhash "^0.1.4" signal-exit "^3.0.7" +ws@7.4.6: + version "7.4.6" + resolved "https://registry.yarnpkg.com/ws/-/ws-7.4.6.tgz#5654ca8ecdeee47c33a9a4bf6d28e2be2980377c" + integrity sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A== + ws@8.12.0, ws@^8.5.0: version "8.12.0" resolved "https://registry.yarnpkg.com/ws/-/ws-8.12.0.tgz#485074cc392689da78e1828a9ff23585e06cddd8"