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"