From 1229f3f4bdd5867ef303a9de649fd9a394ad3907 Mon Sep 17 00:00:00 2001 From: Dmitrii Podlesnyi Date: Tue, 19 Nov 2024 14:07:41 +0900 Subject: [PATCH 1/5] refactor: ledger modal screen reusable structure --- .../Ledger/LedgerConnectionScreen.tsx | 46 +++++---------- .../components/Ledger/LedgerErrorScreen.tsx | 59 +++++-------------- .../components/Ledger/LedgerModalScreen.tsx | 53 +++++++++++++++++ .../icons/LedgerImageDefaultAdaptive.tsx | 12 ++++ .../Ledger/icons/LedgerImageErrorAdaptive.tsx | 12 ++++ 5 files changed, 107 insertions(+), 75 deletions(-) create mode 100644 packages/connect-wallet-modal/src/components/Ledger/LedgerModalScreen.tsx create mode 100644 packages/connect-wallet-modal/src/components/Ledger/icons/LedgerImageDefaultAdaptive.tsx create mode 100644 packages/connect-wallet-modal/src/components/Ledger/icons/LedgerImageErrorAdaptive.tsx diff --git a/packages/connect-wallet-modal/src/components/Ledger/LedgerConnectionScreen.tsx b/packages/connect-wallet-modal/src/components/Ledger/LedgerConnectionScreen.tsx index 7bf983ec..77b0c203 100644 --- a/packages/connect-wallet-modal/src/components/Ledger/LedgerConnectionScreen.tsx +++ b/packages/connect-wallet-modal/src/components/Ledger/LedgerConnectionScreen.tsx @@ -1,38 +1,22 @@ -import React from 'react'; -import { - Loader, - Stack, - StackItem, - Text, - useBreakpoint, -} from '@lidofinance/lido-ui'; -import { LedgerImageDefault } from './icons/LedgerImageDefault'; -import { LedgerImageDefaultMobile } from './icons/LedgerImageDefaultMobile'; -import { LedgerScreenContainerStyled } from './styles'; +import React, { FC } from 'react'; +import { Loader } from '@lidofinance/lido-ui'; import { useLedgerContext } from './hooks'; +import { LedgerModalScreen } from './LedgerModalScreen'; +import { LedgerImageDefaultAdaptive } from './icons/LedgerImageDefaultAdaptive'; export const LedgerConnectionScreen = () => { const { isLoadingLedgerLibs } = useLedgerContext(); + + const message = isLoadingLedgerLibs ? ( + + ) : ( + 'Please connect your Ledger and launch Ethereum app on your device' + ); + return ( - - - - {useBreakpoint('md') ? ( - - ) : ( - - )} - - - {isLoadingLedgerLibs ? ( - - ) : ( - - Please connect your Ledger and launch Ethereum app on your device - - )} - - - + } + message={message} + /> ); }; diff --git a/packages/connect-wallet-modal/src/components/Ledger/LedgerErrorScreen.tsx b/packages/connect-wallet-modal/src/components/Ledger/LedgerErrorScreen.tsx index 6ae00745..e10968e0 100644 --- a/packages/connect-wallet-modal/src/components/Ledger/LedgerErrorScreen.tsx +++ b/packages/connect-wallet-modal/src/components/Ledger/LedgerErrorScreen.tsx @@ -1,50 +1,21 @@ import React, { FC } from 'react'; -import { - Text, - Button, - Stack, - StackItem, - useBreakpoint, -} from '@lidofinance/lido-ui'; -import styled from '@reef-knot/ui-react/styled-wrapper'; -import { LedgerScreenContainerStyled } from './styles'; -import { LedgerImageError } from './icons/LedgerImageError'; -import { LedgerImageErrorMobile } from './icons/LedgerImageErrorMobile'; +import { LedgerModalScreen } from './LedgerModalScreen'; +import { LedgerImageErrorAdaptive } from './icons/LedgerImageErrorAdaptive'; -const HeadingStyled = styled(Text)` - padding-bottom: 4px; -`; +type LedgerErrorScreenProps = { + message: React.ReactNode; + onClickRetry: () => void; +}; -export const LedgerErrorScreen: FC<{ message: string; retry: () => void }> = ({ +export const LedgerErrorScreen: FC = ({ message, - retry, + onClickRetry, }) => ( - - - - - - {useBreakpoint('md') ? ( - - ) : ( - - )} - - - - Something went wrong - - - {message} - - - - - - - - - + } + heading="Something went wrong" + message={message} + action="Retry" + onClickAction={onClickRetry} + /> ); diff --git a/packages/connect-wallet-modal/src/components/Ledger/LedgerModalScreen.tsx b/packages/connect-wallet-modal/src/components/Ledger/LedgerModalScreen.tsx new file mode 100644 index 00000000..cb00814c --- /dev/null +++ b/packages/connect-wallet-modal/src/components/Ledger/LedgerModalScreen.tsx @@ -0,0 +1,53 @@ +import React, { FC } from 'react'; +import { Text, Button, Stack, StackItem } from '@lidofinance/lido-ui'; +import styled from '@reef-knot/ui-react/styled-wrapper'; +import { LedgerScreenContainerStyled } from './styles'; + +const HeadingStyled = styled(Text)` + padding-bottom: 4px; +`; + +type LedgerActionScreenProps = { + icon: React.ReactNode; + heading?: React.ReactNode; + message?: React.ReactNode; + action?: React.ReactNode; + onClickAction?: () => void; +}; + +export const LedgerModalScreen: FC = ({ + icon, + heading, + message, + action, + onClickAction, +}) => ( + + + + + {icon} + + {heading && ( + + {heading} + + )} + {message && ( + + {message} + + )} + + + + {action && ( + + + + )} + + +); diff --git a/packages/connect-wallet-modal/src/components/Ledger/icons/LedgerImageDefaultAdaptive.tsx b/packages/connect-wallet-modal/src/components/Ledger/icons/LedgerImageDefaultAdaptive.tsx new file mode 100644 index 00000000..df885203 --- /dev/null +++ b/packages/connect-wallet-modal/src/components/Ledger/icons/LedgerImageDefaultAdaptive.tsx @@ -0,0 +1,12 @@ +import React from 'react'; +import { useBreakpoint } from '@lidofinance/lido-ui'; +import { LedgerImageDefault } from './LedgerImageDefault'; +import { LedgerImageDefaultMobile } from './LedgerImageDefaultMobile'; + +export const LedgerImageDefaultAdaptive = () => { + return useBreakpoint('md') ? ( + + ) : ( + + ); +}; diff --git a/packages/connect-wallet-modal/src/components/Ledger/icons/LedgerImageErrorAdaptive.tsx b/packages/connect-wallet-modal/src/components/Ledger/icons/LedgerImageErrorAdaptive.tsx new file mode 100644 index 00000000..03affc3a --- /dev/null +++ b/packages/connect-wallet-modal/src/components/Ledger/icons/LedgerImageErrorAdaptive.tsx @@ -0,0 +1,12 @@ +import React from 'react'; +import { useBreakpoint } from '@lidofinance/lido-ui'; +import { LedgerImageError } from './LedgerImageError'; +import { LedgerImageErrorMobile } from './LedgerImageErrorMobile'; + +export const LedgerImageErrorAdaptive = () => { + return useBreakpoint('md') ? ( + + ) : ( + + ); +}; From a5c34b005d74b45354482af44da3241ccf0c1ca2 Mon Sep 17 00:00:00 2001 From: Dmitrii Podlesnyi Date: Tue, 19 Nov 2024 14:10:59 +0900 Subject: [PATCH 2/5] feat: ledger hid connection workaround for browser user activation protection --- .../Ledger/LedgerConnectionScreen.tsx | 12 ++++++- .../src/components/Ledger/LedgerContext.tsx | 34 ++++++++++++++++--- .../src/components/Ledger/LedgerModal.tsx | 21 +++++++++--- 3 files changed, 58 insertions(+), 9 deletions(-) diff --git a/packages/connect-wallet-modal/src/components/Ledger/LedgerConnectionScreen.tsx b/packages/connect-wallet-modal/src/components/Ledger/LedgerConnectionScreen.tsx index 77b0c203..24a7f5cc 100644 --- a/packages/connect-wallet-modal/src/components/Ledger/LedgerConnectionScreen.tsx +++ b/packages/connect-wallet-modal/src/components/Ledger/LedgerConnectionScreen.tsx @@ -4,7 +4,15 @@ import { useLedgerContext } from './hooks'; import { LedgerModalScreen } from './LedgerModalScreen'; import { LedgerImageDefaultAdaptive } from './icons/LedgerImageDefaultAdaptive'; -export const LedgerConnectionScreen = () => { +type LedgerConnectionScreenProps = { + showConnectButton?: boolean; + onClickConnect?: () => void; +}; + +export const LedgerConnectionScreen: FC = ({ + showConnectButton, + onClickConnect, +}) => { const { isLoadingLedgerLibs } = useLedgerContext(); const message = isLoadingLedgerLibs ? ( @@ -17,6 +25,8 @@ export const LedgerConnectionScreen = () => { } message={message} + action={showConnectButton ? 'Connect' : undefined} + onClickAction={showConnectButton ? onClickConnect : undefined} /> ); }; diff --git a/packages/connect-wallet-modal/src/components/Ledger/LedgerContext.tsx b/packages/connect-wallet-modal/src/components/Ledger/LedgerContext.tsx index 8c41e659..7243d605 100644 --- a/packages/connect-wallet-modal/src/components/Ledger/LedgerContext.tsx +++ b/packages/connect-wallet-modal/src/components/Ledger/LedgerContext.tsx @@ -13,6 +13,12 @@ import type Transport from '@ledgerhq/hw-transport'; import { helpers } from '@reef-knot/web3-react'; import { getTransport, isHIDSupported } from './helpers'; +const USER_ACTIVATION_TIMEOUT = 5000; + +type EthConstructorType = new ( + ...args: ConstructorParameters +) => Eth; + export interface LedgerContextProps { isActive: boolean; children?: ReactNode; @@ -23,6 +29,7 @@ export type LedgerContextValue = { ledgerAppEth: MutableRefObject; isTransportConnected: boolean; isLoadingLedgerLibs: boolean; + isUserActivationRequired: boolean; error: Error | null; setError: (e: Error | null) => void; connectTransport: () => Promise; @@ -40,8 +47,10 @@ export const LedgerContextProvider = ({ // isTransportConnecting flag helps with react v18 strict mode in the dev mode, // which re-runs effects extra time, which breaks ledger connection process const isTransportConnecting = useRef(false); + const ledgerLibEth = useRef(null); const ledgerAppEth = useRef(null); const [error, setError] = useState(null); + const [isUserActivationRequired, setUserActivationRequired] = useState(false); const [isTransportConnected, setIsTransportConnected] = useState(false); const [isLoadingLedgerLibs, setIsLoadingLedgerLibs] = useState(false); const [activeAccountsRequestsCounter, setActiveAccountsRequestsCounter] = @@ -52,6 +61,7 @@ export const LedgerContextProvider = ({ await transport?.current?.close(); transport.current = null; ledgerAppEth.current = null; + setUserActivationRequired(false); if (!goingToReconnect) { setIsTransportConnected(false); } @@ -60,9 +70,18 @@ export const LedgerContextProvider = ({ } }, []); + const loadLedgerLibs = useCallback(async () => { + if (ledgerLibEth.current) return; + setIsLoadingLedgerLibs(true); + const { default: Eth } = await import('@ledgerhq/hw-app-eth'); + ledgerLibEth.current = Eth; + setIsLoadingLedgerLibs(false); + }, []); + const connectTransport = useCallback(async () => { if (isTransportConnecting.current || transport.current) return; setError(null); + setUserActivationRequired(false); isTransportConnecting.current = true; if (!isHIDSupported()) { @@ -75,12 +94,17 @@ export const LedgerContextProvider = ({ } try { - setIsLoadingLedgerLibs(true); - const { default: Eth } = await import('@ledgerhq/hw-app-eth'); - setIsLoadingLedgerLibs(false); + const userActivationTime = Date.now(); + await loadLedgerLibs(); + const timePassedAfterUserActivation = Date.now() - userActivationTime; + + if (timePassedAfterUserActivation > USER_ACTIVATION_TIMEOUT) { + setUserActivationRequired(true); + return; + } transport.current = await getTransport(); - ledgerAppEth.current = new Eth(transport.current); + ledgerAppEth.current = new ledgerLibEth.current!(transport.current); await ledgerAppEth.current.getAppConfiguration(); setIsTransportConnected(true); } catch (e: any) { @@ -110,6 +134,7 @@ export const LedgerContextProvider = ({ ledgerAppEth, isTransportConnected, isLoadingLedgerLibs, + isUserActivationRequired, error, setError, connectTransport, @@ -121,6 +146,7 @@ export const LedgerContextProvider = ({ [ isTransportConnected, isLoadingLedgerLibs, + isUserActivationRequired, error, connectTransport, disconnectTransport, diff --git a/packages/connect-wallet-modal/src/components/Ledger/LedgerModal.tsx b/packages/connect-wallet-modal/src/components/Ledger/LedgerModal.tsx index a0af3b25..71382cee 100644 --- a/packages/connect-wallet-modal/src/components/Ledger/LedgerModal.tsx +++ b/packages/connect-wallet-modal/src/components/Ledger/LedgerModal.tsx @@ -33,21 +33,34 @@ export const LedgerModal = (props: LedgerModalProps) => { }; export const LedgerScreen = ({ metrics, onClose }: LedgerModalProps) => { - const { error, reconnectTransport, isTransportConnected } = - useLedgerContext(); + const { + error, + reconnectTransport, + isTransportConnected, + isUserActivationRequired, + } = useLedgerContext(); + + const handleClickRetry = useCallback(() => { + void reconnectTransport(); + }, [reconnectTransport]); return ( {error && ( void reconnectTransport()} + onClickRetry={handleClickRetry} /> )} {!error && isTransportConnected && ( )} - {!error && !isTransportConnected && } + {!error && !isTransportConnected && ( + + )} ); }; From 70ab6f3710fd03bb263bfe5c33b146cbb2229557 Mon Sep 17 00:00:00 2001 From: Dmitrii Podlesnyi Date: Tue, 19 Nov 2024 14:18:32 +0900 Subject: [PATCH 3/5] chore: ledger user activation timeout value adjusted --- .../src/components/Ledger/LedgerContext.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/connect-wallet-modal/src/components/Ledger/LedgerContext.tsx b/packages/connect-wallet-modal/src/components/Ledger/LedgerContext.tsx index 7243d605..d0f63dbb 100644 --- a/packages/connect-wallet-modal/src/components/Ledger/LedgerContext.tsx +++ b/packages/connect-wallet-modal/src/components/Ledger/LedgerContext.tsx @@ -13,7 +13,7 @@ import type Transport from '@ledgerhq/hw-transport'; import { helpers } from '@reef-knot/web3-react'; import { getTransport, isHIDSupported } from './helpers'; -const USER_ACTIVATION_TIMEOUT = 5000; +const USER_ACTIVATION_TIMEOUT = 3000; type EthConstructorType = new ( ...args: ConstructorParameters From 4a389fe2a457f4b1479b3bde5dbab6430177fc87 Mon Sep 17 00:00:00 2001 From: Dmitrii Podlesnyi Date: Thu, 28 Nov 2024 22:06:35 +0900 Subject: [PATCH 4/5] text: ledger loading screen --- .../src/components/Ledger/LedgerConnectionScreen.tsx | 6 +++++- .../connect-wallet-modal/src/components/Ledger/styles.tsx | 7 +++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/packages/connect-wallet-modal/src/components/Ledger/LedgerConnectionScreen.tsx b/packages/connect-wallet-modal/src/components/Ledger/LedgerConnectionScreen.tsx index 24a7f5cc..864e2967 100644 --- a/packages/connect-wallet-modal/src/components/Ledger/LedgerConnectionScreen.tsx +++ b/packages/connect-wallet-modal/src/components/Ledger/LedgerConnectionScreen.tsx @@ -3,6 +3,7 @@ import { Loader } from '@lidofinance/lido-ui'; import { useLedgerContext } from './hooks'; import { LedgerModalScreen } from './LedgerModalScreen'; import { LedgerImageDefaultAdaptive } from './icons/LedgerImageDefaultAdaptive'; +import { LedgerScreenLoadingContainer } from './styles'; type LedgerConnectionScreenProps = { showConnectButton?: boolean; @@ -16,7 +17,10 @@ export const LedgerConnectionScreen: FC = ({ const { isLoadingLedgerLibs } = useLedgerContext(); const message = isLoadingLedgerLibs ? ( - + + +
Loading connector...
+
) : ( 'Please connect your Ledger and launch Ethereum app on your device' ); diff --git a/packages/connect-wallet-modal/src/components/Ledger/styles.tsx b/packages/connect-wallet-modal/src/components/Ledger/styles.tsx index ddd88800..d2c18787 100644 --- a/packages/connect-wallet-modal/src/components/Ledger/styles.tsx +++ b/packages/connect-wallet-modal/src/components/Ledger/styles.tsx @@ -13,3 +13,10 @@ export const LedgerScreenContainerStyled = styled.div` margin: 0 auto; padding: 12px 12px 40px; `; + +export const LedgerScreenLoadingContainer = styled.div` + display: flex; + align-items: center; + justify-content: center; + gap: 10px; +`; From b33a2289983bb23fb6c143c09cef0b1b7fb392c4 Mon Sep 17 00:00:00 2001 From: Dmitrii Podlesnyi Date: Thu, 28 Nov 2024 22:51:20 +0900 Subject: [PATCH 5/5] chore: version updated --- packages/connect-wallet-modal/CHANGELOG.md | 6 ++++++ packages/connect-wallet-modal/package.json | 2 +- packages/reef-knot/CHANGELOG.md | 7 +++++++ packages/reef-knot/package.json | 4 ++-- 4 files changed, 16 insertions(+), 3 deletions(-) diff --git a/packages/connect-wallet-modal/CHANGELOG.md b/packages/connect-wallet-modal/CHANGELOG.md index b8e5ebc3..4f0849e2 100644 --- a/packages/connect-wallet-modal/CHANGELOG.md +++ b/packages/connect-wallet-modal/CHANGELOG.md @@ -1,5 +1,11 @@ # @reef-knot/connect-wallet-modal +## 7.0.1 + +### Patch Changes + +- Ledger HID connection on slow network fixed + ## 7.0.0 ### Major Changes diff --git a/packages/connect-wallet-modal/package.json b/packages/connect-wallet-modal/package.json index 5b813c93..28a4401f 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": "7.0.0", + "version": "7.0.1", "main": "dist/index.js", "types": "dist/index.d.ts", "exports": { diff --git a/packages/reef-knot/CHANGELOG.md b/packages/reef-knot/CHANGELOG.md index 257cbff0..6d2384ec 100644 --- a/packages/reef-knot/CHANGELOG.md +++ b/packages/reef-knot/CHANGELOG.md @@ -1,5 +1,12 @@ # reef-knot +## 7.0.1 + +### Patch Changes + +- Updated dependencies + - @reef-knot/connect-wallet-modal@7.0.1 + ## 7.0.0 ### Major Changes diff --git a/packages/reef-knot/package.json b/packages/reef-knot/package.json index 792287b7..018fd0a1 100644 --- a/packages/reef-knot/package.json +++ b/packages/reef-knot/package.json @@ -1,6 +1,6 @@ { "name": "reef-knot", - "version": "7.0.0", + "version": "7.0.1", "main": "dist/index.js", "types": "dist/index.d.ts", "exports": { @@ -41,7 +41,7 @@ "lint": "eslint --ext ts,tsx,js,mjs ." }, "dependencies": { - "@reef-knot/connect-wallet-modal": "7.0.0", + "@reef-knot/connect-wallet-modal": "7.0.1", "@reef-knot/core-react": "6.0.0", "@reef-knot/web3-react": "6.0.0", "@reef-knot/ui-react": "2.1.5",