diff --git a/apps/demo-react/components/ProviderWeb3WithProps.tsx b/apps/demo-react/components/ProviderWeb3WithProps.tsx index 25d1bdb1..fd6ccde5 100644 --- a/apps/demo-react/components/ProviderWeb3WithProps.tsx +++ b/apps/demo-react/components/ProviderWeb3WithProps.tsx @@ -12,7 +12,7 @@ const supportedChains = [holesky, mainnet, goerli]; const supportedChainsIds = supportedChains.map((chain) => chain.id); const defaultChainId = holesky.id; -const jsonRcpBatchProvider = (chain: Chain) => ({ +const jsonRpcBatchProvider = (chain: Chain) => ({ provider: () => getStaticRpcBatchProvider(chain.id, getRPCPath(chain.id), undefined, 12000), chain, @@ -20,7 +20,7 @@ const jsonRcpBatchProvider = (chain: Chain) => ({ const { chains, provider, webSocketProvider } = configureChains( supportedChains, - [jsonRcpBatchProvider], + [jsonRpcBatchProvider], ); const connectors = getConnectors({ diff --git a/apps/demo-react/config/chains.ts b/apps/demo-react/config/chains.ts index 92bb3f44..f03fd571 100644 --- a/apps/demo-react/config/chains.ts +++ b/apps/demo-react/config/chains.ts @@ -1,4 +1,5 @@ export enum CHAINS { Mainnet = 1, Goerli = 5, + Holesky = 17000, } diff --git a/packages/connect-wallet-modal/CHANGELOG.md b/packages/connect-wallet-modal/CHANGELOG.md index 908b932d..6afebec3 100644 --- a/packages/connect-wallet-modal/CHANGELOG.md +++ b/packages/connect-wallet-modal/CHANGELOG.md @@ -1,5 +1,11 @@ # @reef-knot/connect-wallet-modal +## 1.10.0 + +### Minor Changes + +- Handle connection errors in AcceptTermsModal + ## 1.9.0 ### Minor Changes diff --git a/packages/connect-wallet-modal/package.json b/packages/connect-wallet-modal/package.json index fb298329..d2b2590e 100644 --- a/packages/connect-wallet-modal/package.json +++ b/packages/connect-wallet-modal/package.json @@ -1,6 +1,6 @@ { "name": "@reef-knot/connect-wallet-modal", - "version": "1.9.0", + "version": "1.10.0", "main": "dist/index.js", "types": "dist/index.d.ts", "exports": { @@ -45,12 +45,12 @@ "@types/react-dom": "17" }, "devDependencies": { - "@reef-knot/core-react": "^1.5.1", + "@reef-knot/core-react": "^1.7.0", "@reef-knot/types": "^1.3.0", "@reef-knot/ui-react": "^1.0.7", "@reef-knot/wallets-helpers": "^1.1.5", "@reef-knot/wallets-icons": "^1.2.0", - "@reef-knot/web3-react": "^1.7.0", + "@reef-knot/web3-react": "^1.8.0", "@reef-knot/ledger-connector": "^1.1.0", "@types/ua-parser-js": "^0.7.36", "eslint-config-custom": "*", diff --git a/packages/connect-wallet-modal/src/components/Terms/Terms.tsx b/packages/connect-wallet-modal/src/components/Terms/Terms.tsx index e511d276..aa62e898 100644 --- a/packages/connect-wallet-modal/src/components/Terms/Terms.tsx +++ b/packages/connect-wallet-modal/src/components/Terms/Terms.tsx @@ -3,7 +3,7 @@ import { Checkbox, CheckboxProps, Link } from '@reef-knot/ui-react'; import { TermsStyle, TermsTextStyle } from './styles'; import { Metrics } from '../WalletsModal'; -type WalletModalConnectTermsProps = Pick< +export type WalletModalConnectTermsProps = Pick< CheckboxProps, 'checked' | 'onChange' > & { metrics?: Metrics; termsLink: string; privacyNoticeLink: string }; diff --git a/packages/connect-wallet-modal/src/components/WalletsModal/WalletsModal.tsx b/packages/connect-wallet-modal/src/components/WalletsModal/WalletsModal.tsx index 569157c8..4e79eeb3 100644 --- a/packages/connect-wallet-modal/src/components/WalletsModal/WalletsModal.tsx +++ b/packages/connect-wallet-modal/src/components/WalletsModal/WalletsModal.tsx @@ -1,5 +1,5 @@ -import React, { useCallback, useContext, useState, ReactElement } from 'react'; -import { Button, Modal } from '@reef-knot/ui-react'; +import React, { useCallback, useContext, useState } from 'react'; +import { Modal } from '@reef-knot/ui-react'; import { AcceptTermsModalContext, LS_KEY_TERMS_ACCEPTANCE, @@ -9,12 +9,13 @@ import { ButtonsCommonProps, RequirementsData, } from './types'; -import { Terms } from '../Terms'; -import { WalletsButtonsContainer, CommonButtonsContainer } from './styles'; +import { Terms, WalletModalConnectTermsProps } from '../Terms'; +import { WalletsButtonsContainer } from './styles'; import { NOOP, useLocalStorage } from '../../helpers'; import { LedgerModal } from '../Ledger'; +import { AcceptTermsModal } from './components'; -export function WalletsModal(props: WalletsModalProps): ReactElement { +export function WalletsModal(props: WalletsModalProps) { const { onClose, shouldInvertWalletIcon = false, @@ -33,7 +34,7 @@ export function WalletsModal(props: WalletsModalProps): ReactElement { setTermsChecked((currentValue: boolean) => !currentValue); }, [setTermsChecked]); - const termsProps = { + const termsProps: WalletModalConnectTermsProps = { onChange: handleTermsToggle, checked: termsChecked, termsLink: termsLink || 'https://lido.fi/terms-of-use', @@ -111,25 +112,13 @@ export function WalletsModal(props: WalletsModalProps): ReactElement { if (acceptTermsModal?.isVisible) { return ( - - - - - - + termsProps={termsProps} + termsChecked={termsChecked} + onContinue={acceptTermsModal.onContinue} + error={acceptTermsModal.error} + /> ); } diff --git a/packages/connect-wallet-modal/src/components/WalletsModal/components/AcceptTermsModal.tsx b/packages/connect-wallet-modal/src/components/WalletsModal/components/AcceptTermsModal.tsx new file mode 100644 index 00000000..0de88e6d --- /dev/null +++ b/packages/connect-wallet-modal/src/components/WalletsModal/components/AcceptTermsModal.tsx @@ -0,0 +1,60 @@ +import React from 'react'; +import { Button, Modal } from '@reef-knot/ui-react'; +import styled, { css } from '@reef-knot/ui-react/styled-wrapper'; +import { helpers } from '@reef-knot/web3-react'; +import { Terms, WalletModalConnectTermsProps } from '../../Terms'; +import { CommonButtonsContainer } from '../styles'; +import { useReefKnotContext } from '@reef-knot/core-react'; + +export interface AcceptTermsModalProps { + open: boolean; + termsProps: WalletModalConnectTermsProps; + termsChecked: boolean; + onContinue?: () => unknown; + error: Error | undefined; +} + +const ErrorBlock = styled.div` + ${({ theme: { fontSizesMap, spaceMap, borderRadiusesMap } }) => css` + background: var(--lido-color-error); + color: var(--lido-color-errorContrast); + font-size: ${fontSizesMap.xxs}px; + line-height: 1.6em; + padding: ${spaceMap.lg}px; + margin-top: ${spaceMap.sm}px; + margin-bottom: ${spaceMap.md}px; + border-radius: ${borderRadiusesMap.lg}px; + `} +`; + +export const AcceptTermsModal = ({ + open, + termsProps, + termsChecked, + onContinue, + error, +}: AcceptTermsModalProps) => { + const { chains: supportedChains } = useReefKnotContext(); + let errorMessage = error?.message; + if (error && error.name == 'UnsupportedChainIdError') { + errorMessage = helpers.getUnsupportedChainError(supportedChains).message; + } + + return ( + + + {error && {errorMessage} } + + + + + ); +}; diff --git a/packages/connect-wallet-modal/src/components/WalletsModal/LidoModalLogo.tsx b/packages/connect-wallet-modal/src/components/WalletsModal/components/LidoModalLogo.tsx similarity index 100% rename from packages/connect-wallet-modal/src/components/WalletsModal/LidoModalLogo.tsx rename to packages/connect-wallet-modal/src/components/WalletsModal/components/LidoModalLogo.tsx diff --git a/packages/connect-wallet-modal/src/components/WalletsModal/components/index.ts b/packages/connect-wallet-modal/src/components/WalletsModal/components/index.ts new file mode 100644 index 00000000..77750f7c --- /dev/null +++ b/packages/connect-wallet-modal/src/components/WalletsModal/components/index.ts @@ -0,0 +1,2 @@ +export * from './LidoModalLogo'; +export * from './AcceptTermsModal'; diff --git a/packages/connect-wallet-modal/src/components/WalletsModalForEth/WalletsModalForEth.tsx b/packages/connect-wallet-modal/src/components/WalletsModalForEth/WalletsModalForEth.tsx index c9f3e2c5..49f4e74a 100644 --- a/packages/connect-wallet-modal/src/components/WalletsModalForEth/WalletsModalForEth.tsx +++ b/packages/connect-wallet-modal/src/components/WalletsModalForEth/WalletsModalForEth.tsx @@ -100,9 +100,7 @@ function getWalletsButtons( }); } -export function WalletsModalForEth( - props: WalletsModalForEthProps, -): JSX.Element { +export function WalletsModalForEth(props: WalletsModalForEthProps) { const { walletDataList } = useReefKnotContext(); return ( diff --git a/packages/core-react/CHANGELOG.md b/packages/core-react/CHANGELOG.md index b19f74b3..67062ea2 100644 --- a/packages/core-react/CHANGELOG.md +++ b/packages/core-react/CHANGELOG.md @@ -1,5 +1,11 @@ # @reef-knot/core-react +## 1.7.0 + +### Minor Changes + +- Handle connection errors in AcceptTermsModal + ## 1.6.0 ### Minor Changes diff --git a/packages/core-react/package.json b/packages/core-react/package.json index 2e2b9b0a..cf86921c 100644 --- a/packages/core-react/package.json +++ b/packages/core-react/package.json @@ -1,6 +1,6 @@ { "name": "@reef-knot/core-react", - "version": "1.6.0", + "version": "1.7.0", "main": "dist/index.js", "types": "dist/index.d.ts", "exports": { diff --git a/packages/core-react/src/context/acceptTermsModal.tsx b/packages/core-react/src/context/acceptTermsModal.tsx index 71e577a4..fd66662a 100644 --- a/packages/core-react/src/context/acceptTermsModal.tsx +++ b/packages/core-react/src/context/acceptTermsModal.tsx @@ -6,6 +6,8 @@ export type AcceptTermsModalContextValue = { setVisible: React.Dispatch>; onContinue: () => void; setOnContinue: React.Dispatch void>>; + error?: Error; + setError: React.Dispatch>; }; }; @@ -28,6 +30,8 @@ export const AcceptTermsModalContextProvider: FC = ({ children }) => { () => onContinueDefaultValue, ); + const [error, setError] = useState(undefined); + const contextValue = useMemo( () => ({ acceptTermsModal: { @@ -35,9 +39,11 @@ export const AcceptTermsModalContextProvider: FC = ({ children }) => { setVisible: setIsAcceptTermsModalVisible, onContinue: onAcceptTermsModalContinue, setOnContinue: setOnAcceptTermsModalContinue, + error, + setError, }, }), - [isAcceptTermsModalVisible, onAcceptTermsModalContinue], + [error, isAcceptTermsModalVisible, onAcceptTermsModalContinue], ); return ( diff --git a/packages/core-react/src/context/reefKnot.tsx b/packages/core-react/src/context/reefKnot.tsx index 8aaf7268..7a19f675 100644 --- a/packages/core-react/src/context/reefKnot.tsx +++ b/packages/core-react/src/context/reefKnot.tsx @@ -15,6 +15,7 @@ export interface ReefKnotContextProps { export type ReefKnotContextValue = { rpc: Record; walletDataList: WalletAdapterData[]; + chains: Chain[]; }; export const ReefKnotContext = createContext({} as ReefKnotContextValue); @@ -37,8 +38,9 @@ export const ReefKnot: FC = ({ () => ({ rpc, walletDataList, + chains, }), - [rpc, walletDataList], + [rpc, walletDataList, chains], ); return ( diff --git a/packages/reef-knot/CHANGELOG.md b/packages/reef-knot/CHANGELOG.md index 6c9f228f..0a145c97 100644 --- a/packages/reef-knot/CHANGELOG.md +++ b/packages/reef-knot/CHANGELOG.md @@ -1,5 +1,15 @@ # reef-knot +## 1.10.6 + +### Patch Changes + +- Updated dependencies +- Updated dependencies + - @reef-knot/connect-wallet-modal@1.10.0 + - @reef-knot/core-react@1.7.0 + - @reef-knot/web3-react@1.8.0 + ## 1.10.5 ### Patch Changes diff --git a/packages/reef-knot/package.json b/packages/reef-knot/package.json index 34e94e78..44335138 100644 --- a/packages/reef-knot/package.json +++ b/packages/reef-knot/package.json @@ -1,6 +1,6 @@ { "name": "reef-knot", - "version": "1.10.5", + "version": "1.10.6", "main": "dist/index.js", "types": "dist/index.d.ts", "exports": { @@ -41,9 +41,9 @@ "lint": "eslint --ext ts,tsx,js,mjs ." }, "dependencies": { - "@reef-knot/connect-wallet-modal": "1.9.0", - "@reef-knot/core-react": "1.6.0", - "@reef-knot/web3-react": "1.7.0", + "@reef-knot/connect-wallet-modal": "1.10.0", + "@reef-knot/core-react": "1.7.0", + "@reef-knot/web3-react": "1.8.0", "@reef-knot/ui-react": "1.0.7", "@reef-knot/wallets-icons": "1.2.0", "@reef-knot/wallets-list": "1.6.0", diff --git a/packages/web3-react/CHANGELOG.md b/packages/web3-react/CHANGELOG.md index 387fd6e0..3ca5f009 100644 --- a/packages/web3-react/CHANGELOG.md +++ b/packages/web3-react/CHANGELOG.md @@ -1,5 +1,11 @@ # @reef-knot/web3-react +## 1.8.0 + +### Minor Changes + +- Add holesky to wagmiChainsArray, handle connection errors in AcceptTermsModal + ## 1.7.0 ### Minor Changes diff --git a/packages/web3-react/package.json b/packages/web3-react/package.json index c9995a24..8319c61f 100644 --- a/packages/web3-react/package.json +++ b/packages/web3-react/package.json @@ -1,6 +1,6 @@ { "name": "@reef-knot/web3-react", - "version": "1.7.0", + "version": "1.8.0", "main": "dist/index.js", "types": "dist/index.d.ts", "exports": { @@ -49,7 +49,7 @@ "@lido-sdk/constants": "^3.2.0", "@lido-sdk/providers": "^1.4.13", "@lido-sdk/react": "^2.0.2", - "@reef-knot/core-react": "^1.5.1", + "@reef-knot/core-react": "^1.7.0", "@reef-knot/ledger-connector": "^1.1.0", "@testing-library/react": "^12.1.5", "@testing-library/react-hooks": "^7.0.2", diff --git a/packages/web3-react/src/context/web3.tsx b/packages/web3-react/src/context/web3.tsx index 0981af0b..0dfda39d 100644 --- a/packages/web3-react/src/context/web3.tsx +++ b/packages/web3-react/src/context/web3.tsx @@ -9,7 +9,7 @@ import { CHAINS } from '@lido-sdk/constants'; import { getStaticRpcBatchProvider } from '@lido-sdk/providers'; import { ProviderSDK as ProviderSDKBase } from '@lido-sdk/react'; import { useWeb3React, Web3ReactProvider } from '@web3-react/core'; -import { ReefKnot } from '@reef-knot/core-react'; +import { holesky, ReefKnot } from '@reef-knot/core-react'; import { useAccount } from 'wagmi'; import * as wagmiChains from 'wagmi/chains'; import { SWRConfiguration } from 'swr'; @@ -122,7 +122,7 @@ const ProviderWeb3: FC = (props) => { } = props; const { defaultChainId, supportedChainIds } = props; const connectorsProps = { rpc, appName, appLogoUrl, defaultChainId }; - const wagmiChainsArray = Object.values(wagmiChains); + const wagmiChainsArray = Object.values({ ...wagmiChains, holesky }); const supportedWagmiChains = wagmiChainsArray.filter((chain) => supportedChainIds.includes(chain.id), ); diff --git a/packages/web3-react/src/helpers/index.ts b/packages/web3-react/src/helpers/index.ts index 2d175d1a..755d2d22 100644 --- a/packages/web3-react/src/helpers/index.ts +++ b/packages/web3-react/src/helpers/index.ts @@ -3,3 +3,4 @@ export * from './ua'; export * from './openWindow'; export { default as isUrl } from './isUrl'; export * from './interceptLedgerError'; +export * from './unsupportedChainError'; diff --git a/packages/web3-react/src/helpers/unsupportedChainError.ts b/packages/web3-react/src/helpers/unsupportedChainError.ts new file mode 100644 index 00000000..dce769fc --- /dev/null +++ b/packages/web3-react/src/helpers/unsupportedChainError.ts @@ -0,0 +1,16 @@ +import { Chain } from 'wagmi/chains'; + +export const getUnsupportedChainError = (supportedChains: Chain[]) => { + // Get names of supported chains to suggest them in case of "unsupported network" error + const supportedChainsNames = (() => { + const chains = supportedChains + .map(({ name }) => name) + .filter((chainName) => chainName !== 'unknown'); + const lastChain = chains.pop(); + return [chains.join(', '), lastChain].filter((chain) => chain).join(' or '); + })(); + + return new Error( + `Unsupported chain. Please switch to ${supportedChainsNames} in your wallet and restart the page.`, + ); +}; diff --git a/packages/web3-react/src/hooks/useAutoConnect.ts b/packages/web3-react/src/hooks/useAutoConnect.ts index 6ebb4b54..b932f0ab 100644 --- a/packages/web3-react/src/hooks/useAutoConnect.ts +++ b/packages/web3-react/src/hooks/useAutoConnect.ts @@ -52,11 +52,21 @@ export const useEagerConnector = (connectors: ConnectorsContextValue) => { if (!connector) return; const connectWallet = async () => { - await activate(connector, undefined, true); - // Hide the modal if a user approved the connection in a wallet's UI. - // If a user rejects the connection, then an error is thrown - // and the following code is not being reached, the modal stays visible. - acceptTermsModal.setVisible?.(false); + let error: Error | undefined = undefined; + try { + await activate(connector, undefined, true); + } catch (e) { + error = e as Error; + } + if (shouldAutoConnectApp) { + if (!termsAccepted || error) { + acceptTermsModal.setError?.(error); + acceptTermsModal.setVisible?.(true); + } else { + acceptTermsModal.setVisible?.(false); + acceptTermsModal.setError?.(undefined); + } + } }; let termsAccepted = false; diff --git a/packages/web3-react/src/hooks/useConnectorError.ts b/packages/web3-react/src/hooks/useConnectorError.ts index f440d384..9dd37c4c 100644 --- a/packages/web3-react/src/hooks/useConnectorError.ts +++ b/packages/web3-react/src/hooks/useConnectorError.ts @@ -1,15 +1,23 @@ import { useWeb3 } from './useWeb3'; -import { interceptLedgerError } from '../helpers'; +import { useReefKnotContext } from '@reef-knot/core-react'; +import { interceptLedgerError, getUnsupportedChainError } from '../helpers'; import { useConnectorInfo } from './useConnectorInfo'; +import { useSupportedChains } from './useSupportedChains'; export const useConnectorError = (): Error | undefined => { const { error } = useWeb3(); const { isLedger } = useConnectorInfo(); + const { isUnsupported } = useSupportedChains(); + const { chains: supportedChains } = useReefKnotContext(); if (!error) { return; } + if (isUnsupported) { + return getUnsupportedChainError(supportedChains); + } + if (isLedger) { return interceptLedgerError(error); }