From 051d76ec654c3224d4a6f204730940d399bb3319 Mon Sep 17 00:00:00 2001 From: ahsan-javaiid Date: Tue, 8 Nov 2022 20:15:39 +0500 Subject: [PATCH] feat: rsk ledger integration --- background/constants/networks.ts | 10 +- background/main.ts | 4 + background/redux-slices/ledger.ts | 8 + background/redux-slices/selectors/index.ts | 1 + .../redux-slices/selectors/ledgerSelectors.ts | 5 + background/redux-slices/ui.ts | 22 ++- background/services/ledger/index.ts | 39 ++++- ui/_locales/en/messages.json | 10 +- ui/components/Ledger/LedgerPanelContainer.tsx | 1 + ui/components/Ledger/LedgerSelectNetwork.tsx | 39 +++++ .../LedgerMenu/LedgerMenuProtocolList.tsx | 52 ++++++ .../LedgerMenu/LedgerMenuProtocolListItem.tsx | 156 ++++++++++++++++++ .../OnboardingDerivationPathSelect.tsx | 11 +- ui/pages/Ledger/LedgerImportAccounts.tsx | 21 +-- ui/pages/Ledger/LedgerPrepare.tsx | 32 +++- .../Onboarding/OnboardingImportMetamask.tsx | 3 +- ui/pages/Onboarding/Tabbed/ImportSeed.tsx | 3 +- .../Tabbed/Ledger/LedgerImportAccounts.tsx | 20 +-- .../Tabbed/Ledger/LedgerPrepare.tsx | 96 ++++++----- ui/pages/Onboarding/Tabbed/NewSeed.tsx | 5 +- .../VerifySeed/VerifySeedSuccess.tsx | 3 +- 21 files changed, 437 insertions(+), 104 deletions(-) create mode 100644 ui/components/Ledger/LedgerSelectNetwork.tsx create mode 100644 ui/components/LedgerMenu/LedgerMenuProtocolList.tsx create mode 100644 ui/components/LedgerMenu/LedgerMenuProtocolListItem.tsx diff --git a/background/constants/networks.ts b/background/constants/networks.ts index c75e3f515f..3bff159a55 100644 --- a/background/constants/networks.ts +++ b/background/constants/networks.ts @@ -85,6 +85,8 @@ export const GOERLI: EVMNetwork = { coingeckoPlatformID: "ethereum", } +export const DEFAULT_DERIVATION_PATH = "44'/60'/0'/0/0" + export const DEFAULT_NETWORKS = [ ETHEREUM, POLYGON, @@ -131,7 +133,13 @@ export const TEST_NETWORK_BY_CHAIN_ID = new Set( [GOERLI].map((network) => network.chainID) ) -export const NETWORK_FOR_LEDGER_SIGNING = [ETHEREUM, POLYGON] +export const NETWORK_SUPPORTED_BY_LEDGER = [ + ETHEREUM, + POLYGON, + ROOTSTOCK, + AVALANCHE, + BINANCE_SMART_CHAIN, +] // Networks that are not added to this struct will // not have an in-wallet Swap page diff --git a/background/main.ts b/background/main.ts index 3fc5882d4f..7697a13a7b 100644 --- a/background/main.ts +++ b/background/main.ts @@ -1055,6 +1055,10 @@ export default class Main extends BaseService { this.ledgerService.emitter.on("usbDeviceCount", (usbDeviceCount) => { this.store.dispatch(setUsbDeviceCount({ usbDeviceCount })) }) + + uiSliceEmitter.on("derivationPathChange", (path: string) => { + this.ledgerService.setDefaultDerivationPath(path) + }) } async connectKeyringService(): Promise { diff --git a/background/redux-slices/ledger.ts b/background/redux-slices/ledger.ts index c0ea3f573f..5a8b614fea 100644 --- a/background/redux-slices/ledger.ts +++ b/background/redux-slices/ledger.ts @@ -31,6 +31,7 @@ export type LedgerState = { /** Devices by ID */ devices: Record usbDeviceCount: number + derivationPath?: string } export type Events = { @@ -95,6 +96,12 @@ const ledgerSlice = createSlice({ if (!(deviceID in immerState.devices)) return immerState.currentDeviceID = deviceID }, + setDerivationPath: ( + immerState, + { payload: derivationPath }: { payload: string } + ) => { + immerState.derivationPath = derivationPath + }, setDeviceConnectionStatus: ( immerState, { @@ -224,6 +231,7 @@ export const { addLedgerAccount, setUsbDeviceCount, removeDevice, + setDerivationPath, } = ledgerSlice.actions export default ledgerSlice.reducer diff --git a/background/redux-slices/selectors/index.ts b/background/redux-slices/selectors/index.ts index 3ccee68795..0185299c17 100644 --- a/background/redux-slices/selectors/index.ts +++ b/background/redux-slices/selectors/index.ts @@ -1,5 +1,6 @@ export * from "./activitiesSelectors" export * from "./accountsSelectors" +export * from "./ledgerSelectors" export * from "./keyringsSelectors" export * from "./signingSelectors" export * from "./dappSelectors" diff --git a/background/redux-slices/selectors/ledgerSelectors.ts b/background/redux-slices/selectors/ledgerSelectors.ts index 3c21a47ad3..6697300ad1 100644 --- a/background/redux-slices/selectors/ledgerSelectors.ts +++ b/background/redux-slices/selectors/ledgerSelectors.ts @@ -20,4 +20,9 @@ export const selectLedgerDeviceByAddresses = createSelector( } ) +export const selectLedgerDerivationPath = createSelector( + (state: RootState) => state.ledger.derivationPath, + (path) => path +) + export default {} diff --git a/background/redux-slices/ui.ts b/background/redux-slices/ui.ts index f884ee74b3..9e49c30aad 100644 --- a/background/redux-slices/ui.ts +++ b/background/redux-slices/ui.ts @@ -7,6 +7,7 @@ import { AnalyticsPreferences } from "../services/preferences/types" import { AccountSignerWithId } from "../signing" import { AccountSignerSettings } from "../ui" import { AccountState, addAddressNetwork } from "./accounts" +import { setDerivationPath } from "./ledger" import { createBackgroundAsyncThunk } from "./utils" export const defaultSettings = { @@ -41,6 +42,7 @@ export type Events = { deleteAnalyticsData: never newDefaultWalletValue: boolean refreshBackgroundPage: null + derivationPathChange: string newSelectedAccount: AddressOnNetwork newSelectedAccountSwitched: AddressOnNetwork userActivityEncountered: AddressOnNetwork @@ -256,13 +258,13 @@ export const setSelectedNetwork = createBackgroundAsyncThunk( emitter.emit("newSelectedNetwork", network) // Add any accounts on the currently selected network to the newly // selected network - if those accounts don't yet exist on it. - Object.keys(account.accountsData.evm[currentlySelectedChainID]).forEach( - (address) => { - if (!account.accountsData.evm[network.chainID]?.[address]) { - dispatch(addAddressNetwork({ address, network })) - } + Object.keys( + account.accountsData.evm[currentlySelectedChainID] ?? [] + ).forEach((address) => { + if (!account.accountsData.evm[network.chainID]?.[address]) { + dispatch(addAddressNetwork({ address, network })) } - ) + }) dispatch(setNewSelectedAccount({ ...ui.selectedAccount, network })) } ) @@ -274,6 +276,14 @@ export const refreshBackgroundPage = createBackgroundAsyncThunk( } ) +export const derivationPathChange = createBackgroundAsyncThunk( + "ui/derivationPathChange", + async (derivationPath: string, { dispatch }) => { + await emitter.emit("derivationPathChange", derivationPath) + dispatch(setDerivationPath(derivationPath)) + } +) + export const selectUI = createSelector( (state: { ui: UIState }): UIState => state.ui, (uiState) => uiState diff --git a/background/services/ledger/index.ts b/background/services/ledger/index.ts index 3226bac3df..35de70cb12 100644 --- a/background/services/ledger/index.ts +++ b/background/services/ledger/index.ts @@ -1,5 +1,6 @@ import Transport from "@ledgerhq/hw-transport" import TransportWebUSB from "@ledgerhq/hw-transport-webusb" +import { toChecksumAddress } from "@tallyho/hd-keyring" import Eth from "@ledgerhq/hw-app-eth" import { DeviceModelId } from "@ledgerhq/devices" import { @@ -25,7 +26,11 @@ import { ServiceCreatorFunction, ServiceLifecycleEvents } from "../types" import logger from "../../lib/logger" import { getOrCreateDB, LedgerAccount, LedgerDatabase } from "./db" import { ethersTransactionFromTransactionRequest } from "../chain/utils" -import { NETWORK_FOR_LEDGER_SIGNING } from "../../constants" +import { + NETWORK_SUPPORTED_BY_LEDGER, + ROOTSTOCK, + DEFAULT_DERIVATION_PATH as idDerivationPath, +} from "../../constants" import { normalizeEVMAddress } from "../../lib/utils" import { AddressOnNetwork } from "../../accounts" @@ -111,17 +116,25 @@ type Events = ServiceLifecycleEvents & { usbDeviceCount: number } -export const idDerivationPath = "44'/60'/0'/0/0" - async function deriveAddressOnLedger(path: string, eth: Eth) { const derivedIdentifiers = await eth.getAddress(path) + + if ( + ROOTSTOCK.derivationPath && + path.includes(ROOTSTOCK.derivationPath.slice(0, 8)) + ) { + // ethersGetAddress rejects Rootstock addresses so using toChecksumAddress + return toChecksumAddress(derivedIdentifiers.address, +ROOTSTOCK.chainID) + } + const address = ethersGetAddress(derivedIdentifiers.address) return address } async function generateLedgerId( transport: Transport, - eth: Eth + eth: Eth, + derivationPath: string ): Promise<[string | undefined, LedgerType]> { let extensionDeviceType = LedgerType.UNKNOWN @@ -147,7 +160,7 @@ async function generateLedgerId( return [undefined, extensionDeviceType] } - const address = await deriveAddressOnLedger(idDerivationPath, eth) + const address = await deriveAddressOnLedger(derivationPath, eth) return [address, extensionDeviceType] } @@ -172,6 +185,8 @@ async function generateLedgerId( export default class LedgerService extends BaseService { #currentLedgerId: string | null = null + #derivationPath: string = idDerivationPath + transport: Transport | undefined = undefined #lastOperationPromise = Promise.resolve() @@ -209,7 +224,11 @@ export default class LedgerService extends BaseService { const eth = new Eth(this.transport) - const [id, type] = await generateLedgerId(this.transport, eth) + const [id, type] = await generateLedgerId( + this.transport, + eth, + this.#derivationPath + ) if (!id) { throw new Error("Can't derive meaningful identification address!") @@ -239,7 +258,7 @@ export default class LedgerService extends BaseService { this.emitter.emit("ledgerAdded", { id: this.#currentLedgerId, type, - accountIDs: [idDerivationPath], + accountIDs: [this.#derivationPath], metadata: { ethereumVersion: appData.version, isArbitraryDataSigningEnabled: appData.arbitraryDataEnabled !== 0, @@ -250,6 +269,10 @@ export default class LedgerService extends BaseService { }) } + setDefaultDerivationPath(path: string): void { + this.#derivationPath = path + } + #handleUSBConnect = async (event: USBConnectionEvent): Promise => { this.emitter.emit( "usbDeviceCount", @@ -540,7 +563,7 @@ export default class LedgerService extends BaseService { hexDataToSign: HexString ): Promise { if ( - !NETWORK_FOR_LEDGER_SIGNING.find((supportedNetwork) => + !NETWORK_SUPPORTED_BY_LEDGER.find((supportedNetwork) => sameNetwork(network, supportedNetwork) ) ) { diff --git a/ui/_locales/en/messages.json b/ui/_locales/en/messages.json index f72aa9cd31..c04fa6f8a7 100644 --- a/ui/_locales/en/messages.json +++ b/ui/_locales/en/messages.json @@ -100,6 +100,13 @@ "onlyRejectFromLedger": "Tx can only be Rejected from Ledger", "onboarding": { "connecting": "Connecting...", + "selectLedgerApp": { + "initialScreenHeader": "Select Ledger Live App", + "ecosystem": "{{network}} ecosystem", + "includes": "Includes", + "subheading": "Select which app you would like to start with", + "continueButton": "Continue" + }, "prepare": { "continueButton": "Continue", "tryAgainButton": "Try Again", @@ -113,7 +120,8 @@ "stepsExplainer": "Please follow the steps below and click on Try Again!", "step1": "Plug in a single Ledger", "step2": "Enter pin to unlock", - "step3": "Open Ethereum App" + "step3": "Open {{network}} App", + "derivationPath": "Select derivation path to connect with Ledger" }, "selectDevice": "Select the device", "clickConnect": "Click connect", diff --git a/ui/components/Ledger/LedgerPanelContainer.tsx b/ui/components/Ledger/LedgerPanelContainer.tsx index 54dbb1b38f..3020a9516e 100644 --- a/ui/components/Ledger/LedgerPanelContainer.tsx +++ b/ui/components/Ledger/LedgerPanelContainer.tsx @@ -30,6 +30,7 @@ export default function LedgerPanelContainer({ max-width: 24rem; margin: 0 auto; padding: 1rem; + position: relative; } .indicator { diff --git a/ui/components/Ledger/LedgerSelectNetwork.tsx b/ui/components/Ledger/LedgerSelectNetwork.tsx new file mode 100644 index 0000000000..bebdc7c7dc --- /dev/null +++ b/ui/components/Ledger/LedgerSelectNetwork.tsx @@ -0,0 +1,39 @@ +import React, { ReactElement } from "react" +import { useTranslation } from "react-i18next" +import LedgerContinueButton from "./LedgerContinueButton" +import LedgerPanelContainer from "./LedgerPanelContainer" +import LedgerMenuProtocolList from "../LedgerMenu/LedgerMenuProtocolList" + +export default function LedgerSelectNetwork({ + onContinue, +}: { + onContinue: () => void +}): ReactElement { + const { t } = useTranslation("translation", { + keyPrefix: "ledger.onboarding.selectLedgerApp", + }) + + return ( + +
+ +
+ + {t("continueButton")} + + + +
+ ) +} diff --git a/ui/components/LedgerMenu/LedgerMenuProtocolList.tsx b/ui/components/LedgerMenu/LedgerMenuProtocolList.tsx new file mode 100644 index 0000000000..2a554216e6 --- /dev/null +++ b/ui/components/LedgerMenu/LedgerMenuProtocolList.tsx @@ -0,0 +1,52 @@ +import React, { ReactElement } from "react" +import { + ARBITRUM_ONE, + ETHEREUM, + OPTIMISM, + AVALANCHE, + BINANCE_SMART_CHAIN, + POLYGON, + ROOTSTOCK, +} from "@tallyho/tally-background/constants" +import { sameNetwork } from "@tallyho/tally-background/networks" +import { selectCurrentNetwork } from "@tallyho/tally-background/redux-slices/selectors" +import { useBackgroundSelector } from "../../hooks" +import LedgerMenuProtocolListItem from "./LedgerMenuProtocolListItem" + +const LEDGER_APPS = [ + { + network: ETHEREUM, + ecosystem: [OPTIMISM, ARBITRUM_ONE], + }, + { + network: POLYGON, + }, + { + network: ROOTSTOCK, + }, + { + network: AVALANCHE, + }, + { + network: BINANCE_SMART_CHAIN, + }, +] + +export default function LedgerMenuProtocolList(): ReactElement { + const currentNetwork = useBackgroundSelector(selectCurrentNetwork) + + return ( +
+
    + {LEDGER_APPS.map((info) => ( + + ))} +
+
+ ) +} diff --git a/ui/components/LedgerMenu/LedgerMenuProtocolListItem.tsx b/ui/components/LedgerMenu/LedgerMenuProtocolListItem.tsx new file mode 100644 index 0000000000..d9309a9b77 --- /dev/null +++ b/ui/components/LedgerMenu/LedgerMenuProtocolListItem.tsx @@ -0,0 +1,156 @@ +import React, { ReactElement } from "react" +import { useTranslation } from "react-i18next" +import classNames from "classnames" +import { useDispatch } from "react-redux" +import { + setSelectedNetwork, + derivationPathChange, +} from "@tallyho/tally-background/redux-slices/ui" +import { EVMNetwork } from "@tallyho/tally-background/networks" +import { + ETHEREUM, + ROOTSTOCK, + DEFAULT_DERIVATION_PATH, +} from "@tallyho/tally-background/constants" +import SharedNetworkIcon from "../Shared/SharedNetworkIcon" + +interface Props { + network: EVMNetwork + ecosystem?: EVMNetwork[] + isSelected: boolean +} + +export default function LedgerMenuProtocolListItem(props: Props): ReactElement { + const { t } = useTranslation("translation", { + keyPrefix: "ledger.onboarding.selectLedgerApp", + }) + const { isSelected, network, ecosystem } = props + const dispatch = useDispatch() + + const onNetworkSelect = () => { + dispatch(setSelectedNetwork(network)) + + if (network.derivationPath && network.chainID === ROOTSTOCK.chainID) { + dispatch(derivationPathChange(network.derivationPath)) + } else { + dispatch(derivationPathChange(DEFAULT_DERIVATION_PATH)) + } + } + + return ( +
  • +
    +
    + +
    + {ecosystem && ( +
    + {ecosystem.map((ecosystemNetwork) => ( + + ))} +
    + )} +
    +
    +
    + {network.chainID === ETHEREUM.chainID + ? t("ecosystem", { network: network.name }) + : network.name} +
    + {network.chainID === ETHEREUM.chainID && ( + + {t("includes")} + {ecosystem && + ecosystem.map(({ name }) => ( + + {name} + + ))} + + )} +
    + +
  • + ) +} + +LedgerMenuProtocolListItem.defaultProps = { + isSelected: false, +} diff --git a/ui/components/Onboarding/OnboardingDerivationPathSelect.tsx b/ui/components/Onboarding/OnboardingDerivationPathSelect.tsx index 4d5241b055..f29c1558fd 100644 --- a/ui/components/Onboarding/OnboardingDerivationPathSelect.tsx +++ b/ui/components/Onboarding/OnboardingDerivationPathSelect.tsx @@ -5,12 +5,14 @@ import React, { useRef, useState, } from "react" +import { selectLedgerDerivationPath } from "@tallyho/tally-background/redux-slices/selectors" import { useTranslation } from "react-i18next" import { i18n } from "../../_locales/i18n" import SharedButton from "../Shared/SharedButton" import SharedInput from "../Shared/SharedInput" import SharedModal from "../Shared/SharedModal" import SharedSelect, { Option } from "../Shared/SharedSelect" +import { useBackgroundSelector } from "../../hooks" // TODO make this network specific const initialDerivationPaths: Option[] = [ @@ -55,11 +57,16 @@ export default function OnboardingDerivationPathSelect({ }): ReactElement { const { t } = useTranslation("translation", { keyPrefix: "onboarding" }) const [derivationPaths, setDerivationPaths] = useState(initialDerivationPaths) - + const ledgerDerivationPath = useBackgroundSelector(selectLedgerDerivationPath) const [modalStep, setModalStep] = useState(0) const [customPath, setCustomPath] = useState(initialCustomPath) const [customPathLabel, setCustomPathLabel] = useState("") - const [defaultIndex, setDefaultIndex] = useState() + const selectedIndex = initialDerivationPaths.findIndex( + (path) => path.value === `m/${ledgerDerivationPath}` + ) + const [defaultIndex, setDefaultIndex] = useState( + selectedIndex === -1 ? 0 : selectedIndex + ) // Reset value to display placeholder after adding a custom path const customPathValue = customPath.isReset diff --git a/ui/pages/Ledger/LedgerImportAccounts.tsx b/ui/pages/Ledger/LedgerImportAccounts.tsx index 210d6ac8e4..a61d71d693 100644 --- a/ui/pages/Ledger/LedgerImportAccounts.tsx +++ b/ui/pages/Ledger/LedgerImportAccounts.tsx @@ -9,12 +9,12 @@ import classNames from "classnames" import React, { ReactElement, useEffect, useState } from "react" import { selectCurrentNetwork } from "@tallyho/tally-background/redux-slices/selectors" import { EVMNetwork } from "@tallyho/tally-background/networks" +import { DEFAULT_DERIVATION_PATH } from "@tallyho/tally-background/constants" import { useTranslation } from "react-i18next" import { useBackgroundDispatch, useBackgroundSelector } from "../../hooks" import SharedButton from "../../components/Shared/SharedButton" import LedgerContinueButton from "../../components/Ledger/LedgerContinueButton" import LedgerPanelContainer from "../../components/Ledger/LedgerPanelContainer" -import OnboardingDerivationPathSelectAlt from "../../components/Onboarding/OnboardingDerivationPathSelect" import { scanWebsite } from "../../utils/constants" const addressesPerPage = 6 @@ -378,22 +378,15 @@ export default function LedgerImportAccounts({ const { t } = useTranslation("translation", { keyPrefix: "ledger.onboarding", }) - const [parentPath, setParentPath] = useState(null) + const selectedNetwork = useBackgroundSelector(selectCurrentNetwork) + const parentPath = selectedNetwork.derivationPath ?? DEFAULT_DERIVATION_PATH return ( <> -
    - { - setParentPath(value) - }} - /> -
    {parentPath !== null && ( )}
    - ) } diff --git a/ui/pages/Ledger/LedgerPrepare.tsx b/ui/pages/Ledger/LedgerPrepare.tsx index b26e5f9239..4e46045b23 100644 --- a/ui/pages/Ledger/LedgerPrepare.tsx +++ b/ui/pages/Ledger/LedgerPrepare.tsx @@ -1,7 +1,11 @@ -import React, { ReactElement } from "react" +import React, { ReactElement, useState } from "react" import { useTranslation } from "react-i18next" +import { selectCurrentNetwork } from "@tallyho/tally-background/redux-slices/selectors" import LedgerContinueButton from "../../components/Ledger/LedgerContinueButton" import LedgerPanelContainer from "../../components/Ledger/LedgerPanelContainer" +import SharedIcon from "../../components/Shared/SharedIcon" +import { useBackgroundSelector } from "../../hooks" +import LedgerSelectNetwork from "../../components/Ledger/LedgerSelectNetwork" export default function LedgerPrepare({ onContinue, @@ -15,12 +19,19 @@ export default function LedgerPrepare({ const { t } = useTranslation("translation", { keyPrefix: "ledger.onboarding.prepare", }) + const selectedNetwork = useBackgroundSelector(selectCurrentNetwork) const buttonLabel = initialScreen ? t("continueButton") : t("tryAgainButton") const subHeadingWord = initialScreen ? t("subheadingWord1") : t("subheadingWord2") const warningText = deviceCount === 0 ? t("noLedgerConnected") : t("multipleLedgersConnected") + const [isNetworkSelected, setIsNetworkSelected] = useState(false) + + if (!isNetworkSelected) { + return setIsNetworkSelected(true)} /> + } + return ( + {isNetworkSelected && ( + { + e.stopPropagation() + setIsNetworkSelected(false) + }} + customStyles={` + position: absolute; + top: 45px; + left: -45px; + `} + /> + )} {!initialScreen && deviceCount !== 1 ? (
    @@ -45,7 +73,7 @@ export default function LedgerPrepare({
    1. {t("step1")}
    2. {t("step2")}
    3. -
    4. {t("step3")}
    5. +
    6. {t("step3", { network: selectedNetwork.name })}
    {buttonLabel} diff --git a/ui/pages/Onboarding/OnboardingImportMetamask.tsx b/ui/pages/Onboarding/OnboardingImportMetamask.tsx index 8cdb60cfec..f02624cd85 100644 --- a/ui/pages/Onboarding/OnboardingImportMetamask.tsx +++ b/ui/pages/Onboarding/OnboardingImportMetamask.tsx @@ -4,6 +4,7 @@ import { useHistory } from "react-router-dom" import { isValidMnemonic } from "@ethersproject/hdnode" import classNames from "classnames" import { FeatureFlags, isEnabled } from "@tallyho/tally-background/features" +import { DEFAULT_DERIVATION_PATH } from "@tallyho/tally-background/constants" import { useTranslation } from "react-i18next" import { selectCurrentNetwork } from "@tallyho/tally-background/redux-slices/selectors" import SharedButton from "../../components/Shared/SharedButton" @@ -113,7 +114,7 @@ export default function OnboardingImportMetamask(props: Props): ReactElement { const [recoveryPhrase, setRecoveryPhrase] = useState("") const [errorMessage, setErrorMessage] = useState("") const [path, setPath] = useState( - selectedNetwork.derivationPath ?? "m/44'/60'/0'/0" + selectedNetwork.derivationPath ?? DEFAULT_DERIVATION_PATH ) const [isImporting, setIsImporting] = useState(false) diff --git a/ui/pages/Onboarding/Tabbed/ImportSeed.tsx b/ui/pages/Onboarding/Tabbed/ImportSeed.tsx index b4fb5429d7..b136f8bccc 100644 --- a/ui/pages/Onboarding/Tabbed/ImportSeed.tsx +++ b/ui/pages/Onboarding/Tabbed/ImportSeed.tsx @@ -3,6 +3,7 @@ import { importKeyring } from "@tallyho/tally-background/redux-slices/keyrings" import { Redirect, useHistory } from "react-router-dom" import { isValidMnemonic } from "@ethersproject/hdnode" import { FeatureFlags, isEnabled } from "@tallyho/tally-background/features" +import { DEFAULT_DERIVATION_PATH } from "@tallyho/tally-background/constants" import { useTranslation } from "react-i18next" import { selectCurrentNetwork } from "@tallyho/tally-background/redux-slices/selectors" import SharedButton from "../../../components/Shared/SharedButton" @@ -26,7 +27,7 @@ export default function ImportSeed(props: Props): ReactElement { const [recoveryPhrase, setRecoveryPhrase] = useState("") const [errorMessage, setErrorMessage] = useState("") const [path, setPath] = useState( - selectedNetwork.derivationPath ?? "m/44'/60'/0'/0" + selectedNetwork.derivationPath ?? DEFAULT_DERIVATION_PATH ) const [isImporting, setIsImporting] = useState(false) diff --git a/ui/pages/Onboarding/Tabbed/Ledger/LedgerImportAccounts.tsx b/ui/pages/Onboarding/Tabbed/Ledger/LedgerImportAccounts.tsx index e09ea5ec1d..0560444307 100644 --- a/ui/pages/Onboarding/Tabbed/Ledger/LedgerImportAccounts.tsx +++ b/ui/pages/Onboarding/Tabbed/Ledger/LedgerImportAccounts.tsx @@ -10,11 +10,11 @@ import React, { ReactElement, useEffect, useState } from "react" import { selectCurrentNetwork } from "@tallyho/tally-background/redux-slices/selectors" import { EVMNetwork } from "@tallyho/tally-background/networks" import { useTranslation } from "react-i18next" +import { DEFAULT_DERIVATION_PATH } from "@tallyho/tally-background/constants" import { useBackgroundDispatch, useBackgroundSelector } from "../../../../hooks" import SharedButton from "../../../../components/Shared/SharedButton" import LedgerContinueButton from "../../../../components/Ledger/LedgerContinueButton" import LedgerPanelContainer from "../../../../components/Ledger/LedgerPanelContainer" -import OnboardingDerivationPathSelectAlt from "../../../../components/Onboarding/OnboardingDerivationPathSelect" import { scanWebsite } from "../../../../utils/constants" const addressesPerPage = 6 @@ -370,7 +370,8 @@ export default function LedgerImportAccounts({ const { t } = useTranslation("translation", { keyPrefix: "ledger.onboarding", }) - const [parentPath, setParentPath] = useState(null) + const selectedNetwork = useBackgroundSelector(selectCurrentNetwork) + const parentPath = selectedNetwork.derivationPath ?? DEFAULT_DERIVATION_PATH return ( <> @@ -379,13 +380,6 @@ export default function LedgerImportAccounts({ heading={t("selectLedgeraccounts")} subHeading={t("connectSelectedLedger")} > -
    - { - setParentPath(value) - }} - /> -
    {parentPath !== null && ( )} - ) } diff --git a/ui/pages/Onboarding/Tabbed/Ledger/LedgerPrepare.tsx b/ui/pages/Onboarding/Tabbed/Ledger/LedgerPrepare.tsx index 04c2949411..73fbc6e3d7 100644 --- a/ui/pages/Onboarding/Tabbed/Ledger/LedgerPrepare.tsx +++ b/ui/pages/Onboarding/Tabbed/Ledger/LedgerPrepare.tsx @@ -1,7 +1,11 @@ -import React, { ReactElement } from "react" +import React, { ReactElement, useState } from "react" import { useTranslation } from "react-i18next" +import { selectCurrentNetwork } from "@tallyho/tally-background/redux-slices/selectors" import LedgerContinueButton from "../../../../components/Ledger/LedgerContinueButton" import LedgerPanelContainer from "../../../../components/Ledger/LedgerPanelContainer" +import SharedIcon from "../../../../components/Shared/SharedIcon" +import { useBackgroundSelector } from "../../../../hooks" +import LedgerSelectNetwork from "../../../../components/Ledger/LedgerSelectNetwork" export default function LedgerPrepare({ onContinue, @@ -15,14 +19,19 @@ export default function LedgerPrepare({ const { t } = useTranslation("translation", { keyPrefix: "ledger.onboarding.prepare", }) + const selectedNetwork = useBackgroundSelector(selectCurrentNetwork) const buttonLabel = initialScreen ? t("continueButton") : t("tryAgainButton") const subHeadingWord = initialScreen ? t("subheadingWord1") : t("subheadingWord2") const warningText = deviceCount === 0 ? t("noLedgerConnected") : t("multipleLedgersConnected") + const [isNetworkSelected, setIsNetworkSelected] = useState(false) + + if (!isNetworkSelected) { + return setIsNetworkSelected(true)} /> + } - const showError = !initialScreen && deviceCount !== 1 return ( -
    - {showError ? ( -
    -
    - - {warningText} -
    -
    -

    {t("stepsExplainer")}

    -
    + {isNetworkSelected && ( + { + e.stopPropagation() + setIsNetworkSelected(false) + }} + customStyles={` + position: absolute; + top: 45px; + left: -45px; + `} + /> + )} + {!initialScreen && deviceCount !== 1 ? ( +
    +
    + + {warningText} +
    +
    +

    {t("stepsExplainer")}

    - ) : ( - <> - )} -
      -
    1. {t("step1")}
    2. -
    3. {t("step2")}
    4. -
    5. {t("step3")}
    6. -
    - - {buttonLabel} - -
    +
    + ) : ( + <> + )} +
      +
    1. {t("step1")}
    2. +
    3. {t("step2")}
    4. +
    5. {t("step3", { network: selectedNetwork.name })}
    6. +
    + + {buttonLabel} +