diff --git a/apps/governance/src/components/vega-wallet-dialogs/vega-wallet-dialogs.tsx b/apps/governance/src/components/vega-wallet-dialogs/vega-wallet-dialogs.tsx index 2c8ce90cd..4a0c8ad37 100644 --- a/apps/governance/src/components/vega-wallet-dialogs/vega-wallet-dialogs.tsx +++ b/apps/governance/src/components/vega-wallet-dialogs/vega-wallet-dialogs.tsx @@ -1,12 +1,61 @@ +import { useCallback } from 'react'; +import { useLocalStorage } from '@vegaprotocol/react-helpers'; import { VegaConnectDialog, VegaManageDialog } from '@vegaprotocol/wallet'; import { AppStateActionType, useAppState, } from '../../contexts/app-state/app-state-context'; import { Connectors } from '../../lib/vega-connectors'; +import { t } from '@vegaprotocol/i18n'; +import { ExternalLink, Icon } from '@vegaprotocol/ui-toolkit'; +import Routes from '../../routes/routes'; + +export const RISK_ACCEPTED_KEY = 'vega_risk_accepted'; + +const RiskMessage = () => { + return ( + <> +
+ +
+

+ {t( + 'By using the Vega Console, you acknowledge that you have read and understood the' + )}{' '} + + + {t('Vega Console Disclaimer')} + + + + . +

+ + ); +}; export const VegaWalletDialogs = () => { const { appState, appDispatch } = useAppState(); + + const [riskAcceptedValue, setValue] = useLocalStorage(RISK_ACCEPTED_KEY); + const onRiskAcknowledge = useCallback(() => { + setValue('true'); + }, [setValue]); + return ( <> { isOpen: open, }) } + riskMessage={riskAcceptedValue === 'true' ? undefined : } + onRiskAcknowledge={ + riskAcceptedValue === 'true' ? undefined : onRiskAcknowledge + } /> { + useDocumentTitle(name); + return ( +
+
+

+ {t('Disclaimer')} +

+

+ {t( + 'Vega is a decentralised peer-to-peer protocol that can be used to create liquidity and trade derivatives of cryptocurrencies. The Vega Protocol is an implementation layer (layer one) protocol made of free, public, open-source or source-available software. Use of the Vega Protocol involves various risks, including but not limited to, losses while digital assets are being supplied to the Vega Protocol and losses due to the fluctuation of prices of assets. Before using the Vega Protocol, you should review the relevant documentation to make sure that you understand how it works. dditionally, just as you can access email protocols such as SMTP through multiple email clients, ou can potentially access the Vega Protocol through dozens of web or mobile interfaces. You are responsible for doing your own diligence on those interfaces to understand the associated risks and any fees.' + )} +

+

+ {t( + 'As described in the Vega Protocol core license, the Vega Protocol is provided "as is", at your own risk, and without warranties of any kind. Although Gobalsky Labs Limited developed much of the initial code for the Vega Protocol, it does not provide or control the Vega Protocol, which is run by third parties deploying it on a bespoke blockchain. Upgrades and modifications to the Vega Protocol are managed in a community-driven way by holders of the VEGA governance token.' + )} +

+

+ {t( + 'No developer or entity involved in creating the Vega Protocol will be liable for any claims or damages whatsoever associated with your use, inability to use, or your interaction with other users of the Vega Protocol, including any direct, indirect, incidental, special, exemplary, punitive or consequential damages, or legal costs, or loss of profits, cryptocurrencies, tokens or anything else of value.' + )} +

+

+ {t( + 'This website is not located on the world wide web and its data is not stored on servers - physical or virtual. It is located on a decentralised network, the Interplanetary File System ("IPFS"). The IPFS decentralised web is made up of all the computers (nodes) connected to it. Data is therefore stored on many different computers. No party is the operator or hoster of this website. The information provided on this website does not constitute investment advice, financial advice, trading advice, or any other sort of advice and you should not treat any of the website\'s content as such. No party recommends that any cryptocurrency asset should be bought, sold, or held by you via this website. Do conduct your own due diligence and consult our financial advisor before making any investment decisions.' + )} +

+
+
+ ); +}; + +export default Disclaimer; diff --git a/apps/governance/src/routes/router-config.tsx b/apps/governance/src/routes/router-config.tsx index c7ff06c7a..9fcee2d92 100644 --- a/apps/governance/src/routes/router-config.tsx +++ b/apps/governance/src/routes/router-config.tsx @@ -207,6 +207,13 @@ const LazyWithdrawals = React.lazy( ) ); +const LazyDisclaimer = React.lazy( + () => + import( + /* webpackChunkName: "route-disclaimer", webpackPrefetch: true */ './disclaimer' + ) +); + const redirects = [ { path: Routes.VALIDATORS, @@ -345,6 +352,10 @@ const routerConfig = [ path: Routes.CONTRACTS, element: , }, + { + path: Routes.DISCLAIMER, + element: , + }, { path: '*', // Not lazy as loaded when a user first hits the site diff --git a/apps/governance/src/routes/routes.ts b/apps/governance/src/routes/routes.ts index 61b276758..0a93e9af8 100644 --- a/apps/governance/src/routes/routes.ts +++ b/apps/governance/src/routes/routes.ts @@ -14,6 +14,7 @@ const Routes = { SUPPLY: '/token/tranches', ASSOCIATE: '/token/associate', DISASSOCIATE: '/token/disassociate', + DISCLAIMER: '/disclaimer', }; export default Routes; diff --git a/apps/trading/client-pages/disclaimer/disclaimer.tsx b/apps/trading/client-pages/disclaimer/disclaimer.tsx new file mode 100644 index 000000000..a69ea57f0 --- /dev/null +++ b/apps/trading/client-pages/disclaimer/disclaimer.tsx @@ -0,0 +1,33 @@ +import { t } from '@vegaprotocol/i18n'; + +export const Disclaimer = () => { + return ( +
+
+

+ {t('Disclaimer')} +

+

+ {t( + 'Vega is a decentralised peer-to-peer protocol that can be used to create liquidity and trade derivatives of cryptocurrencies. The Vega Protocol is an implementation layer (layer one) protocol made of free, public, open-source or source-available software. Use of the Vega Protocol involves various risks, including but not limited to, losses while digital assets are being supplied to the Vega Protocol and losses due to the fluctuation of prices of assets. Before using the Vega Protocol, you should review the relevant documentation to make sure that you understand how it works. dditionally, just as you can access email protocols such as SMTP through multiple email clients, ou can potentially access the Vega Protocol through dozens of web or mobile interfaces. You are responsible for doing your own diligence on those interfaces to understand the associated risks and any fees.' + )} +

+

+ {t( + 'As described in the Vega Protocol core license, the Vega Protocol is provided "as is", at your own risk, and without warranties of any kind. Although Gobalsky Labs Limited developed much of the initial code for the Vega Protocol, it does not provide or control the Vega Protocol, which is run by third parties deploying it on a bespoke blockchain. Upgrades and modifications to the Vega Protocol are managed in a community-driven way by holders of the VEGA governance token.' + )} +

+

+ {t( + 'No developer or entity involved in creating the Vega Protocol will be liable for any claims or damages whatsoever associated with your use, inability to use, or your interaction with other users of the Vega Protocol, including any direct, indirect, incidental, special, exemplary, punitive or consequential damages, or legal costs, or loss of profits, cryptocurrencies, tokens or anything else of value.' + )} +

+

+ {t( + 'This website is not located on the world wide web and its data is not stored on servers - physical or virtual. It is located on a decentralised network, the Interplanetary File System ("IPFS"). The IPFS decentralised web is made up of all the computers (nodes) connected to it. Data is therefore stored on many different computers. No party is the operator or hoster of this website. The information provided on this website does not constitute investment advice, financial advice, trading advice, or any other sort of advice and you should not treat any of the website\'s content as such. No party recommends that any cryptocurrency asset should be bought, sold, or held by you via this website. Do conduct your own due diligence and consult our financial advisor before making any investment decisions.' + )} +

+
+
+ ); +}; diff --git a/apps/trading/client-pages/disclaimer/index.ts b/apps/trading/client-pages/disclaimer/index.ts new file mode 100644 index 000000000..c47c92bfc --- /dev/null +++ b/apps/trading/client-pages/disclaimer/index.ts @@ -0,0 +1,3 @@ +import { Disclaimer } from './disclaimer'; + +export default Disclaimer; diff --git a/apps/trading/components/navbar/navbar.tsx b/apps/trading/components/navbar/navbar.tsx index 40f9ef088..1a5fc3e93 100644 --- a/apps/trading/components/navbar/navbar.tsx +++ b/apps/trading/components/navbar/navbar.tsx @@ -38,10 +38,7 @@ export const Navbar = ({ const { GITHUB_FEEDBACK_URL } = useEnvironment(); const tokenLink = useLinks(DApp.Token); const marketId = useGlobalStore((store) => store.marketId); - const update = useGlobalStore((store) => store.update); - const showDisclaimer = useCallback(() => { - update({ shouldDisplayDisclaimerDialog: true }); - }, [update]); + const tradingPath = marketId ? Links[Routes.MARKET](marketId) : Links[Routes.MARKET](); @@ -113,9 +110,7 @@ export const Navbar = ({ {t('Disclaimer')} diff --git a/apps/trading/components/welcome-dialog/disclaimer.tsx b/apps/trading/components/welcome-dialog/disclaimer.tsx deleted file mode 100644 index 4332b4623..000000000 --- a/apps/trading/components/welcome-dialog/disclaimer.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import { t } from '@vegaprotocol/i18n'; - -export const Disclaimer = () => { - return ( - <> -

- {t( - 'Vega is a decentralised peer-to-peer protocol that can be used to create liquidity and trade derivatives of cryptocurrencies. The Vega Protocol is an implementation layer (layer one) protocol made of free, public, open-source or source-available software. Use of the Vega Protocol involves various risks, including but not limited to, losses while digital assets are being supplied to the Vega Protocol and losses due to the fluctuation of prices of assets. Before using the Vega Protocol, you should review the relevant documentation to make sure that you understand how it works. dditionally, just as you can access email protocols such as SMTP through multiple email clients, ou can potentially access the Vega Protocol through dozens of web or mobile interfaces. You are responsible for doing your own diligence on those interfaces to understand the associated risks and any fees.' - )} -

-

- {t( - 'As described in the Vega Protocol core license, the Vega Protocol is provided "as is", at your own risk, and without warranties of any kind. Although Gobalsky Labs Limited developed much of the initial code for the Vega Protocol, it does not provide or control the Vega Protocol, which is run by third parties deploying it on a bespoke blockchain. Upgrades and modifications to the Vega Protocol are managed in a community-driven way by holders of the VEGA governance token.' - )} -

-

- {t( - 'No developer or entity involved in creating the Vega Protocol will be liable for any claims or damages whatsoever associated with your use, inability to use, or your interaction with other users of the Vega Protocol, including any direct, indirect, incidental, special, exemplary, punitive or consequential damages, or legal costs, or loss of profits, cryptocurrencies, tokens or anything else of value.' - )} -

-

- {t( - 'This website is not located on the world wide web and its data is not stored on servers - physical or virtual. It is located on a decentralised network, the Interplanetary File System ("IPFS"). The IPFS decentralised web is made up of all the computers (nodes) connected to it. Data is therefore stored on many different computers. No party is the operator or hoster of this website. The information provided on this website does not constitute investment advice, financial advice, trading advice, or any other sort of advice and you should not treat any of the website\'s content as such. No party recommends that any cryptocurrency asset should be bought, sold, or held by you via this website. Do conduct your own due diligence and consult our financial advisor before making any investment decisions.' - )} -

- - ); -}; diff --git a/apps/trading/components/welcome-dialog/welcome-dialog.tsx b/apps/trading/components/welcome-dialog/welcome-dialog.tsx index bc57616fc..8571103d8 100644 --- a/apps/trading/components/welcome-dialog/welcome-dialog.tsx +++ b/apps/trading/components/welcome-dialog/welcome-dialog.tsx @@ -9,7 +9,6 @@ import * as constants from '../constants'; import { RiskNoticeDialog } from './risk-notice-dialog'; import { WelcomeNoticeDialog } from './welcome-notice-dialog'; import { WelcomeLandingDialog } from './welcome-landing-dialog'; -import { Disclaimer } from './disclaimer'; import { useGlobalStore } from '../../stores'; import { useEnvironment } from '@vegaprotocol/environment'; import { Networks } from '@vegaprotocol/environment'; @@ -31,15 +30,10 @@ export const WelcomeDialog = () => { const shouldDisplayWelcomeDialog = useGlobalStore( (store) => store.shouldDisplayWelcomeDialog ); - const shouldDisplayDisclaimerDialog = useGlobalStore( - (store) => store.shouldDisplayDisclaimerDialog - ); - const shouldDisplayMainnetRiskDialog = useGlobalStore( - (store) => store.shouldDisplayMainnetRiskDialog - ); + const isRiskDialogNeeded = riskAccepted !== 'true' && - (VEGA_ENV !== Networks.MAINNET || shouldDisplayMainnetRiskDialog) && + VEGA_ENV !== Networks.MAINNET && !('Cypress' in window); const isWelcomeDialogNeeded = pathname === '/' || shouldDisplayWelcomeDialog; @@ -50,12 +44,7 @@ export const WelcomeDialog = () => { isRiskDialogNeeded && VEGA_ENV !== Networks.MAINNET, }); }, [update, isRiskDialogNeeded, VEGA_ENV]); - if (shouldDisplayDisclaimerDialog) { - title = t('Disclaimer'); - dialogContent = ; - size = 'medium'; - onClose = () => update({ shouldDisplayDisclaimerDialog: false }); - } else if (isRiskDialogNeeded) { + if (isRiskDialogNeeded) { dialogContent = ( ); diff --git a/apps/trading/pages/client-router.tsx b/apps/trading/pages/client-router.tsx index 4180df127..d23532827 100644 --- a/apps/trading/pages/client-router.tsx +++ b/apps/trading/pages/client-router.tsx @@ -30,6 +30,10 @@ const LazySettings = dynamic(() => import('../client-pages/settings'), { ssr: false, }); +const LazyDisclaimer = dynamic(() => import('../client-pages/disclaimer'), { + ssr: false, +}); + export enum Routes { HOME = '/', MARKET = '/markets', @@ -37,6 +41,7 @@ export enum Routes { PORTFOLIO = '/portfolio', LIQUIDITY = 'liquidity/:marketId', SETTINGS = 'settings', + DISCLAIMER = 'disclaimer', } type ConsoleLinks = { [r in Routes]: (...args: string[]) => string }; @@ -51,6 +56,7 @@ export const Links: ConsoleLinks = { ? trimEnd(`${Routes.LIQUIDITY}/${marketId}`, '/') : Routes.LIQUIDITY, [Routes.SETTINGS]: () => Routes.SETTINGS, + [Routes.DISCLAIMER]: () => Routes.DISCLAIMER, }; const routerConfig: RouteObject[] = [ @@ -97,6 +103,10 @@ const routerConfig: RouteObject[] = [ path: Routes.SETTINGS, element: , }, + { + path: Routes.DISCLAIMER, + element: , + }, { path: '*', element: ( diff --git a/apps/trading/pages/dialogs-container.tsx b/apps/trading/pages/dialogs-container.tsx index e9562a4d9..31326e732 100644 --- a/apps/trading/pages/dialogs-container.tsx +++ b/apps/trading/pages/dialogs-container.tsx @@ -9,25 +9,63 @@ import { DepositDialog } from '@vegaprotocol/deposits'; import { Web3ConnectUncontrolledDialog } from '@vegaprotocol/web3'; import { WelcomeDialog } from '../components/welcome-dialog'; import { TransferDialog } from '@vegaprotocol/accounts'; -import { useGlobalStore } from '../stores'; import { useCallback } from 'react'; import { useLocalStorage } from '@vegaprotocol/react-helpers'; -import * as constants from '../components/constants'; +import { t } from '@vegaprotocol/i18n'; +import { ExternalLink, Icon } from '@vegaprotocol/ui-toolkit'; +import { RISK_ACCEPTED_KEY } from '../components/constants'; +import { Links, Routes } from './client-router'; + +const RiskMessage = () => { + return ( + <> +
+
    +
  • + {t( + 'No party hosts or operates this IFPS website or offers any financial advice.' + )} +
  • +
  • + {t( + 'You may encounter bugs, loss of functionality or loss of assets.' + )} +
  • +
  • + {t('No party accepts any liability for any losses whatsoever.')} +
  • +
+
+

+ {t( + 'By using the Vega Console, you acknowledge that you have read and understood the' + )}{' '} + + + {t('Vega Console Disclaimer')} + + + + . +

+ + ); +}; const DialogsContainer = () => { const { isOpen, id, trigger, setOpen } = useAssetDetailsDialogStore(); - const [riskAccepted] = useLocalStorage(constants.RISK_ACCEPTED_KEY); - const update = useGlobalStore((store) => store.update); - const openRiskDialog = useCallback(() => { - if (riskAccepted !== 'true') { - update({ shouldDisplayMainnetRiskDialog: true }); - } - }, [update, riskAccepted]); + const [riskAcceptedValue, setValue] = useLocalStorage(RISK_ACCEPTED_KEY); + const onRiskAcknowledge = useCallback(() => { + setValue('true'); + }, [setValue]); return ( <> } + onRiskAcknowledge={ + riskAcceptedValue === 'true' ? undefined : onRiskAcknowledge + } /> void; + riskMessage?: React.ReactNode; + onRiskAcknowledge?: () => void; } export const useVegaWalletDialogStore = create()( @@ -60,26 +62,22 @@ export interface VegaWalletDialogStore { export const VegaConnectDialog = ({ connectors, onChangeOpen, + riskMessage, + onRiskAcknowledge, }: VegaConnectDialogProps) => { const vegaWalletDialogOpen = useVegaWalletDialogStore( (store) => store.vegaWalletDialogOpen ); - const updateVegaWalletDialog = useVegaWalletDialogStore((store) => - onChangeOpen - ? (open: boolean) => { - store.updateVegaWalletDialog(open); - onChangeOpen(open); - } - : store.updateVegaWalletDialog - ); - const closeVegaWalletDialog = useVegaWalletDialogStore((store) => - onChangeOpen - ? () => { - store.closeVegaWalletDialog(); - onChangeOpen(false); - } - : store.closeVegaWalletDialog + const updateVegaWalletDialog = useVegaWalletDialogStore( + (store) => (open: boolean) => { + store.updateVegaWalletDialog(open); + onChangeOpen?.(open); + } ); + const closeVegaWalletDialog = useVegaWalletDialogStore((store) => () => { + store.closeVegaWalletDialog(); + onChangeOpen?.(false); + }); const { data, error, loading } = useChainIdQuery(); @@ -112,6 +110,8 @@ export const VegaConnectDialog = ({ connectors={connectors} closeDialog={closeVegaWalletDialog} appChainId={data.statistics.chainId} + riskMessage={riskMessage} + onRiskAcknowledge={onRiskAcknowledge} /> ); }; @@ -131,16 +131,20 @@ const ConnectDialogContainer = ({ connectors, closeDialog, appChainId, + riskMessage, + onRiskAcknowledge, }: { connectors: Connectors; closeDialog: () => void; appChainId: string; + riskMessage?: React.ReactNode; + onRiskAcknowledge?: () => void; }) => { const { VEGA_WALLET_URL, VEGA_ENV, HOSTED_WALLET_URL } = useEnvironment(); const [selectedConnector, setSelectedConnector] = useState(); const [walletUrl, setWalletUrl] = useState(VEGA_WALLET_URL || ''); const [walletType, setWalletType] = useState(); - + const isMainnet = VEGA_ENV === Networks.MAINNET; const reset = useCallback(() => { setSelectedConnector(undefined); setWalletType(undefined); @@ -151,8 +155,13 @@ const ConnectDialogContainer = ({ closeDialog(); }, CLOSE_DELAY); }, [closeDialog]); - - const { connect, ...jsonRpcState } = useJsonRpcConnect(delayedOnConnect); + const needsAcknowledge = Boolean( + isMainnet && riskMessage && onRiskAcknowledge + ); + const { connect, ...jsonRpcState } = useJsonRpcConnect( + delayedOnConnect, + needsAcknowledge + ); const handleSelect = (type: WalletType, isHosted = false) => { let connector; @@ -189,13 +198,15 @@ const ConnectDialogContainer = ({ onConnect={closeDialog} appChainId={appChainId} reset={reset} + riskMessage={riskMessage} + onRiskAcknowledge={onRiskAcknowledge} /> ) : ( ); }; @@ -255,6 +266,8 @@ const SelectedForm = ({ jsonRpcState, reset, onConnect, + riskMessage, + onRiskAcknowledge, }: { type: WalletType; connector: VegaConnector; @@ -265,6 +278,8 @@ const SelectedForm = ({ }; reset: () => void; onConnect: () => void; + riskMessage?: React.ReactNode; + onRiskAcknowledge?: () => void; }) => { if (connector instanceof RestConnector) { return ( @@ -317,6 +332,8 @@ const SelectedForm = ({ onConnect={onConnect} appChainId={appChainId} reset={reset} + riskMessage={riskMessage} + onRiskAcknowledge={onRiskAcknowledge} /> diff --git a/libs/wallet/src/connect-dialog/json-rpc-connector-form.tsx b/libs/wallet/src/connect-dialog/json-rpc-connector-form.tsx index 9766b69e5..d1f720eca 100644 --- a/libs/wallet/src/connect-dialog/json-rpc-connector-form.tsx +++ b/libs/wallet/src/connect-dialog/json-rpc-connector-form.tsx @@ -1,6 +1,7 @@ import capitalize from 'lodash/capitalize'; import { t } from '@vegaprotocol/i18n'; import { + Button, ButtonLink, Diamond, Link, @@ -14,6 +15,7 @@ import { ClientErrors } from '../connectors'; import { ConnectDialogTitle } from './connect-dialog-elements'; import { Status } from '../use-json-rpc-connect'; import { DocsLinks } from '@vegaprotocol/environment'; +import { useVegaWallet } from '../use-vega-wallet'; export const ServiceErrors = { NO_HEALTHY_NODE: 1000, @@ -26,6 +28,9 @@ export const JsonRpcConnectorForm = ({ status, error, reset, + onConnect, + riskMessage, + onRiskAcknowledge, }: { connector: JsonRpcConnector; appChainId: string; @@ -33,35 +38,14 @@ export const JsonRpcConnectorForm = ({ error: WalletClientError | null; onConnect: () => void; reset: () => void; + riskMessage?: React.ReactNode; + onRiskAcknowledge?: () => void; }) => { + const { disconnect } = useVegaWallet(); if (status === Status.Idle) { return null; } - return ( - - ); -}; - -const Connecting = ({ - status, - error, - connector, - appChainId, - reset, -}: { - status: Status; - error: WalletClientError | null; - connector: JsonRpcConnector; - appChainId: string; - reset: () => void; -}) => { if (status === Status.Error) { return ( { + onRiskAcknowledge?.(); + onConnect(); + }; + const handleDisagree = () => { + disconnect(); + onConnect(); + }; + return ( + <> + {t('Understand the risk')} + {riskMessage} +
+
+ +
+
+ +
+
+ + ); + } return null; }; diff --git a/libs/wallet/src/use-json-rpc-connect.ts b/libs/wallet/src/use-json-rpc-connect.ts index 05e0c4c97..8db760a98 100644 --- a/libs/wallet/src/use-json-rpc-connect.ts +++ b/libs/wallet/src/use-json-rpc-connect.ts @@ -13,9 +13,13 @@ export enum Status { ListingKeys = 'ListingKeys', Connected = 'Connected', Error = 'Error', + NeedsAcknowledge = 'NeedAcknowledge', } -export const useJsonRpcConnect = (onConnect: () => void) => { +export const useJsonRpcConnect = ( + onConnect: () => void, + needsAcknowledge?: boolean +) => { const { connect } = useVegaWallet(); const [status, setStatus] = useState(Status.Idle); const [error, setError] = useState(null); @@ -52,9 +56,12 @@ export const useJsonRpcConnect = (onConnect: () => void) => { // Call connect in the wallet provider. The connector will be stored for // future actions such as sending transactions await connect(connector); - - setStatus(Status.Connected); - onConnect(); + if (needsAcknowledge) { + setStatus(Status.NeedsAcknowledge); + } else { + setStatus(Status.Connected); + onConnect(); + } } catch (err) { if (err instanceof WalletClientError) { setError(err); @@ -62,7 +69,7 @@ export const useJsonRpcConnect = (onConnect: () => void) => { setStatus(Status.Error); } }, - [onConnect, connect] + [onConnect, connect, needsAcknowledge] ); return {