Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ledger live implementation #515

Merged
merged 32 commits into from
Aug 16, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
37d51a7
Add Ledger Live connector
michalsmiarowski May 15, 2023
4da9032
Add LedgerLive button to SelectWallet modal
michalsmiarowski May 15, 2023
42d139b
Create ConnectLedgerLive component
michalsmiarowski May 15, 2023
27053bc
Fix typings in ledger_live connector
michalsmiarowski May 15, 2023
9b1eff2
Add `@ledgerhq/connect-kit-loader` package
michalsmiarowski May 15, 2023
d2a1af9
Add `LEDGER_LIVE` to `WalletType` enum
michalsmiarowski May 15, 2023
f7be6fa
Add proper Ledger Live icon
michalsmiarowski May 17, 2023
131ab84
Add listeners to the provider
michalsmiarowski May 17, 2023
740de82
Fix error then disconnectin the Ledger wallet.
michalsmiarowski May 17, 2023
d7ed01b
Change console.log to console.error
michalsmiarowski May 25, 2023
869f9ac
Add empty line
michalsmiarowski May 25, 2023
f936566
Remove duplicated code
michalsmiarowski May 30, 2023
c235c98
Use correct Ledger Live icon
michalsmiarowski May 30, 2023
1149fa5
Rename ledger_live connector
michalsmiarowski May 30, 2023
f1fac17
Remove unnecessary undefined.
michalsmiarowski May 30, 2023
36b0767
Create `ConnectorNotAcivatedError` error
michalsmiarowski May 30, 2023
6ccab86
Close walletconnection modal for LedgerLive
michalsmiarowski Jun 5, 2023
225800e
Pass rpc to contructor of ledger Live
michalsmiarowski Jun 6, 2023
6f909fc
Use `useColorModeValue` hook
michalsmiarowski Jun 8, 2023
bc69060
Merge branch 'main' into ledger-live-implementation
michalsmiarowski Jun 9, 2023
f6ff7f5
Add alert for unsupported network
michalsmiarowski Jun 12, 2023
eaaa1b6
Merge branch 'main' into ledger-live-implementation
michalsmiarowski Jul 24, 2023
df848ca
Update @ledgerhq/connect-kit-loader lib
michalsmiarowski Jul 24, 2023
66224b1
Adjust `checkSupport` method for new lib version
michalsmiarowski Jul 24, 2023
aaacbe7
Make code more readable
michalsmiarowski Jul 24, 2023
ab114c9
Simplify wallet connection aler useEffect
michalsmiarowski Jul 24, 2023
3bf7da1
Add `shouldForceCloseModal` property
michalsmiarowski Jul 25, 2023
98a6086
Add `shouldForceCloseModal` to dependency array
michalsmiarowski Jul 26, 2023
e3f46f9
Add feature flag for ledger live
michalsmiarowski Jul 27, 2023
0853ce8
Pass project id through a constructor
michalsmiarowski Jul 27, 2023
1f996cd
Update `@ledgerhq/connect-kit-loader`
michalsmiarowski Aug 11, 2023
6cfe182
Fix "Cannot convert undefined or null to object"
michalsmiarowski Aug 14, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .env
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ REACT_APP_FEATURE_FLAG_MULTI_APP_STAKING=true
REACT_APP_FEATURE_FLAG_FEEDBACK_MODULE=false
REACT_APP_FEATURE_FLAG_POSTHOG=false
REACT_APP_FEATURE_FLAG_SENTRY=$SENTRY_SUPPORT
REACT_APP_FEATURE_FLAG_LEDGER_LIVE=true
REACT_APP_SENTRY_DSN=$SENTRY_DSN

REACT_APP_ELECTRUM_PROTOCOL=$ELECTRUM_PROTOCOL
Expand Down
1 change: 1 addition & 0 deletions .env.production
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ REACT_APP_FEATURE_FLAG_POSTHOG=$POSTHOG_SUPPORT
REACT_APP_POSTHOG_API_KEY=$POSTHOG_API_KEY
REACT_APP_POSTHOG_HOSTNAME_HTTP=$POSTHOG_HOSTNAME_HTTP
REACT_APP_FEATURE_FLAG_SENTRY=$SENTRY_SUPPORT
REACT_APP_FEATURE_FLAG_LEDGER_LIVE=true
REACT_APP_SENTRY_DSN=$SENTRY_DSN

REACT_APP_ELECTRUM_PROTOCOL=$ELECTRUM_PROTOCOL
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
"@keep-network/tbtc": "development",
"@keep-network/tbtc-v2": "development",
"@keep-network/tbtc-v2.ts": "development",
"@ledgerhq/connect-kit-loader": "^1.1.2",
"@reduxjs/toolkit": "^1.6.1",
"@rehooks/local-storage": "^2.4.4",
"@sentry/react": "^7.33.0",
Expand Down
43 changes: 43 additions & 0 deletions src/components/Modal/SelectWalletModal/ConnectLedgerLive.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { FC } from "react"
import { useWeb3React } from "@web3-react/core"
import { ledgerLive } from "../../../web3/connectors"
import { WalletConnectionModalBase } from "./components"
import { ConnectionError, WalletType } from "../../../enums"
import doesErrorInclude from "../../../web3/utils/doesErrorInclude"
import { LedgerLight } from "../../../static/icons/LedgerLight"
import { LedgerDark } from "../../../static/icons/LedgerDark"
import { useColorModeValue } from "@threshold-network/components"

const ConnectLedgerLive: FC<{ goBack: () => void; closeModal: () => void }> = ({
goBack,
closeModal,
}) => {
const { activate, error } = useWeb3React()

const connectionRejected = doesErrorInclude(
error,
ConnectionError.RejectedMetamaskConnection
)

const walletIcon = useColorModeValue(LedgerLight, LedgerDark)

return (
<WalletConnectionModalBase
connector={ledgerLive}
goBack={goBack}
closeModal={closeModal}
WalletIcon={walletIcon}
title="Ledger Live"
subTitle={
!error
? "The Ledger Live extension will open in an external window."
: ""
}
tryAgain={connectionRejected ? () => activate(ledgerLive) : undefined}
walletType={WalletType.LedgerLive}
shouldForceCloseModal
/>
)
}

export default ConnectLedgerLive
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ const ConnectWalletConnect: FC<{
activate(walletConnect)
}}
walletType={WalletType.WalletConnect}
shouldForceCloseModal
>
<WalletConnectStatusAlert
connectionRejected={connectionRejected}
Expand Down
41 changes: 22 additions & 19 deletions src/components/Modal/SelectWalletModal/InitialSelection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,26 +18,29 @@ const InitialWalletSelection: FC<{
}> = ({ walletOptions, onSelect }) => {
return (
<VStack divider={<StackDivider margin="0 40px !important" />}>
{walletOptions.map((opt) => (
<Button
key={opt.id}
variant="unstyled"
w="100%"
h="100px"
_hover={{ bg: useColorModeValue("gray.100", "gray.500") }}
_active={{ bg: "gray.300" }}
borderRadius={0}
onClick={() => onSelect(opt.id)}
>
<Stack justify="space-between" direction="row" px="40px">
<Stack direction="row">
<Icon as={opt.icon} h="40px" w="40px" mr="32px" />
<H4>{opt.title}</H4>
{walletOptions.map((opt) => {
const icon = useColorModeValue(opt.icon.light, opt.icon.dark)
return (
<Button
key={opt.id}
variant="unstyled"
w="100%"
h="100px"
_hover={{ bg: useColorModeValue("gray.100", "gray.500") }}
_active={{ bg: "gray.300" }}
borderRadius={0}
onClick={() => onSelect(opt.id)}
>
<Stack justify="space-between" direction="row" px="40px">
<Stack direction="row">
<Icon as={icon} h="40px" w="40px" mr="32px" />
<H4>{opt.title}</H4>
</Stack>
<Icon as={BiRightArrowAlt} h="40px" w="40px" />
</Stack>
<Icon as={BiRightArrowAlt} h="40px" w="40px" />
</Stack>
</Button>
))}
</Button>
)
})}
</VStack>
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,14 @@ interface Props extends BaseModalProps {
goBack: () => void
connector?: AbstractConnector
walletType: WalletType
/**
* This is required for some of the providers (for example WalletConnect v2),
* because they have their own modal that is being opened. In that case we
* can't display our loading modal because it has larger z-index than
* provider's one and it's too problematic to change that.
*
*/
shouldForceCloseModal?: boolean
}

const WalletConnectionModalBase: FC<Props> = ({
Expand All @@ -40,6 +48,7 @@ const WalletConnectionModalBase: FC<Props> = ({
onContinue,
connector,
walletType,
shouldForceCloseModal,
}) => {
const { activate, active, account } = useWeb3React()
const captureWalletConnected = useCapture(PosthogEvent.WalletConnected)
Expand All @@ -49,8 +58,14 @@ const WalletConnectionModalBase: FC<Props> = ({

captureWalletConnected({ walletType })
activate(connector)
if (walletType === WalletType.WalletConnect) closeModal()
}, [activate, connector, captureWalletConnected, walletType])
if (shouldForceCloseModal) closeModal()
}, [
activate,
connector,
captureWalletConnected,
walletType,
shouldForceCloseModal,
])

return (
<>
Expand Down
38 changes: 34 additions & 4 deletions src/components/Modal/SelectWalletModal/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,27 +16,55 @@ import { CoinbaseWallet } from "../../../static/icons/CoinbaseWallet"
import { useModal } from "../../../hooks/useModal"
import ModalCloseButton from "../ModalCloseButton"
import ConnectTaho from "./ConnectTaho"
import ConnectLedgerLive from "./ConnectLedgerLive"
import { LedgerLight } from "../../../static/icons/LedgerLight"
import { LedgerDark } from "../../../static/icons/LedgerDark"
import { featureFlags } from "../../../constants"

const walletOptions: WalletOption[] = [
{
id: WalletType.TAHO,
title: "Taho",
icon: Taho,
icon: {
light: Taho,
dark: Taho,
},
},
{
id: WalletType.Metamask,
title: "MetaMask",
icon: MetaMaskIcon,
icon: {
light: MetaMaskIcon,
dark: MetaMaskIcon,
},
},
...(featureFlags.LEDGER_LIVE
? [
{
id: WalletType.LedgerLive,
title: "Ledger Live",
icon: {
light: LedgerLight,
dark: LedgerDark,
},
},
]
: []),
{
id: WalletType.WalletConnect,
title: "WalletConnect",
icon: WalletConnectIcon,
icon: {
light: WalletConnectIcon,
dark: WalletConnectIcon,
},
},
{
id: WalletType.Coinbase,
title: "Coinbase Wallet",
icon: CoinbaseWallet,
icon: {
light: CoinbaseWallet,
dark: CoinbaseWallet,
},
},
]

Expand Down Expand Up @@ -94,6 +122,8 @@ const ConnectWallet: FC<{
return <ConnectWalletConnect goBack={goBack} closeModal={onClose} />
case WalletType.Coinbase:
return <ConnectCoinbase goBack={goBack} closeModal={onClose} />
case WalletType.LedgerLive:
return <ConnectLedgerLive goBack={goBack} closeModal={onClose} />
default:
return <></>
}
Expand Down
34 changes: 21 additions & 13 deletions src/components/Navbar/WalletConnectionAlert.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,41 +4,49 @@ import {
AlertIcon,
CloseButton,
} from "@chakra-ui/react"
import { FC, useEffect, useMemo, useState } from "react"
import { FC, useEffect, useState } from "react"
import isSupportedNetwork from "../../utils/isSupportedNetwork"
import chainIdToNetworkName from "../../utils/chainIdToNetworkName"
import { supportedChainId } from "../../utils/getEnvVariable"
import { useWeb3React } from "@web3-react/core"

const WalletConnectionAlert: FC<{
account?: string | null
chainId?: number
}> = ({ account, chainId }) => {
const [hideAlert, setHideAlert] = useState(false)
const { error } = useWeb3React()
const [alertDescription, setAlertDescription] = useState("")

const alertDescription = useMemo(() => {
if (!account) {
const errorMessage = error?.message

useEffect(() => {
if (errorMessage) {
setAlertDescription(errorMessage)
setHideAlert(false)
return
}

if (!isSupportedNetwork(chainId)) {
return `Your wallet is on an unsupported network. Switch to the ${chainIdToNetworkName(
supportedChainId
)} network`
}
}, [account, chainId])

useEffect(() => {
if (!account || (account && isSupportedNetwork(chainId))) {
setHideAlert(true)
return
}

if (!isSupportedNetwork(chainId)) {
setAlertDescription(
`Your wallet is on an unsupported network. Switch to the ${chainIdToNetworkName(
supportedChainId
)} network`
)
setHideAlert(false)
return
}
}, [account, chainId])
}, [account, chainId, errorMessage])

const resetAlert = () => {
setHideAlert(true)
setAlertDescription("")
}

if (hideAlert) {
return null
Expand All @@ -60,7 +68,7 @@ const WalletConnectionAlert: FC<{
position="absolute"
right="8px"
top="8px"
onClick={() => setHideAlert(true)}
onClick={resetAlert}
/>
</Alert>
)
Expand Down
3 changes: 3 additions & 0 deletions src/constants/featureFlags.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,6 @@ export const SENTRY = getEnvVariable(EnvVariable.FEATURE_FLAG_SENTRY) === "true"

export const TBTC_V2_REDEMPTION =
getEnvVariable(EnvVariable.FEATURE_FLAG_TBTC_V2_REDEMPTION) === "true"

export const LEDGER_LIVE =
getEnvVariable(EnvVariable.FEATURE_FLAG_LEDGER_LIVE) === "true"
1 change: 1 addition & 0 deletions src/enums/env.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ const envVariables = [
"FEATURE_FLAG_MULTI_APP_STAKING",
"FEATURE_FLAG_POSTHOG",
"FEATURE_FLAG_FEEDBACK_MODULE",
"FEATURE_FLAG_LEDGER_LIVE",
"POSTHOG_HOSTNAME_HTTP",
"POSTHOG_API_KEY",
"ELECTRUM_PROTOCOL",
Expand Down
1 change: 1 addition & 0 deletions src/enums/web3.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,5 @@ export enum WalletType {
Metamask = "METAMASK",
WalletConnect = "WALLET_CONNECT",
Coinbase = "COINBASE",
LedgerLive = "LEDGER_LIVE",
}
21 changes: 21 additions & 0 deletions src/static/icons/LedgerDark.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { createIcon } from "@chakra-ui/icons"

export const LedgerDark = createIcon({
displayName: "Ledger",
viewBox: "0 0 160 160",
path: (
<svg
width="160"
height="160"
viewBox="0 0 160 160"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<rect width="160" height="160" rx="16" fill="#00000D" />
<path
d="M93.1482 119.207V125H135V98.8769H128.902V119.207H93.1482ZM93.1482 33V38.792H128.902V59.1231H135V33H93.1482ZM74.0104 59.1231H67.9125V98.8769H95.4153V93.6539H74.0104V59.1231ZM26 98.8769V125H67.8518V119.207H32.0979V98.8769H26ZM26 33V59.1231H32.0979V38.792H67.8518V33H26Z"
fill="white"
/>
</svg>
),
})
21 changes: 21 additions & 0 deletions src/static/icons/LedgerLight.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { createIcon } from "@chakra-ui/icons"

export const LedgerLight = createIcon({
displayName: "Ledger",
viewBox: "0 0 160 160",
path: (
<svg
width="160"
height="160"
viewBox="0 0 160 160"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<rect width="160" height="160" rx="16" fill="white" />
<path
d="M93.1482 119.207V125H135V98.8769H128.902V119.207H93.1482ZM93.1482 33V38.792H128.902V59.1231H135V33H93.1482ZM74.0104 59.1231H67.9125V98.8769H95.4153V93.6539H74.0104V59.1231ZM26 98.8769V125H67.8518V119.207H32.0979V98.8769H26ZM26 33V59.1231H32.0979V38.792H67.8518V33H26Z"
fill="#00000D"
/>
</svg>
),
})
Comment on lines +1 to +21
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like the svg is the same we only swap colors in <rect fill={} and <path fill={} />. So we can create one file
LedgerLive.tsx and create an custom icon using Icon component see https://chakra-ui.com/docs/components/icon#using-the-icon-component:

const LedgerLive = ({ bgColor, iconColor }) => {
 <Icon viewBox >
        <rect width="160" height="160" rx="16" fill={bgColor} />
      <path
        d="M93.1482 119.207V125H135V98.8769H128.902V119.207H93.1482ZM93.1482 33V38.792H128.902V59.1231H135V33H93.1482ZM74.0104 59.1231H67.9125V98.8769H95.4153V93.6539H74.0104V59.1231ZM26 98.8769V125H67.8518V119.207H32.0979V98.8769H26ZM26 33V59.1231H32.0979V38.792H67.8518V33H26Z"
        fill="{iconColor}"
      />
 </Icon>
}

export const LedgerLiveDark = () => <LedgerLive bgColor={#00000D} iconColor={white} />

export const LedgerLiveLight = () => <LedgerLive bgColor={white} iconColor={#00000D} />

5 changes: 4 additions & 1 deletion src/types/wallet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ import { WalletType } from "../enums"

export interface WalletOption {
id: WalletType
icon: FC
title: string
icon: {
light: FC
dark: FC
}
}
1 change: 1 addition & 0 deletions src/web3/connectors/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@ export * from "./taho"
export * from "./metamask"
export * from "./walletConnect"
export * from "./coinbaseWallet"
export * from "./ledgerLive"
export { AbstractConnector } from "@web3-react/abstract-connector"
export { UserRejectedRequestError } from "@web3-react/injected-connector"
Loading
Loading