-
Notifications
You must be signed in to change notification settings - Fork 11.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[wallet-ext] hook up the "Connect to Ledger" modal to actually connec…
…t to an external Ledger device (#9061) ## Description This PR enables users to be able to connect to their external Ledger device by hitting "Continue" in the "Connect Ledger" modal. I added some error handling and loading states as well. One important thing to call out here is how we're managing the state of the ledger client - for now, we'll maintain a context instead of using global variables/adding the ledger client as a Redux thunk extra so that the client instance is reactive and has generally more expected behavior. Failed connection attempts: <video src="https://user-images.githubusercontent.com/7453188/224116008-f6b5d644-5c55-4eea-9997-88e3d4662550.mov"> Successful connection attempt: <video src="https://user-images.githubusercontent.com/7453188/224116020-d82bdfb2-95e9-4724-9889-5f14a58ddd33.mov"> ## Test Plan - Manual testing --- If your changes are not user-facing and not a breaking change, you can skip the following section. Otherwise, please indicate what changed, and then add to the Release Notes section as highlighted during the release process. ### Type of Change (Check all that apply) - [ ] user-visible impact - [ ] breaking change for a client SDKs - [ ] breaking change for FNs (FN binary must upgrade) - [ ] breaking change for validators or node operators (must upgrade binaries) - [ ] breaking change for on-chain data layout - [ ] necessitate either a data wipe or data migration ### Release notes N/A
- Loading branch information
1 parent
3a4393e
commit 08beb3a
Showing
11 changed files
with
235 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
16 changes: 16 additions & 0 deletions
16
apps/wallet/src/ui/app/components/ledger/LedgerExceptions.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
// Copyright (c) Mysten Labs, Inc. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
export class LedgerConnectionFailedError extends Error { | ||
constructor(message: string) { | ||
super(message); | ||
Object.setPrototypeOf(this, LedgerConnectionFailedError.prototype); | ||
} | ||
} | ||
|
||
export class LedgerNoTransportMechanismError extends Error { | ||
constructor(message: string) { | ||
super(message); | ||
Object.setPrototypeOf(this, LedgerNoTransportMechanismError.prototype); | ||
} | ||
} |
112 changes: 112 additions & 0 deletions
112
apps/wallet/src/ui/app/components/ledger/SuiLedgerClientProvider.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
// Copyright (c) Mysten Labs, Inc. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
import TransportWebHID from '@ledgerhq/hw-transport-webhid'; | ||
import TransportWebUSB from '@ledgerhq/hw-transport-webusb'; | ||
import SuiLedgerClient from '@mysten/ledgerjs-hw-app-sui'; | ||
import { | ||
createContext, | ||
useCallback, | ||
useContext, | ||
useEffect, | ||
useMemo, | ||
useState, | ||
} from 'react'; | ||
|
||
import { | ||
LedgerConnectionFailedError, | ||
LedgerNoTransportMechanismError, | ||
} from './LedgerExceptions'; | ||
|
||
import type Transport from '@ledgerhq/hw-transport'; | ||
|
||
type SuiLedgerClientProviderProps = { | ||
children: React.ReactNode; | ||
}; | ||
|
||
type SuiLedgerClientContextValue = [ | ||
SuiLedgerClient | undefined, | ||
() => Promise<SuiLedgerClient> | ||
]; | ||
|
||
const SuiLedgerClientContext = createContext< | ||
SuiLedgerClientContextValue | undefined | ||
>(undefined); | ||
|
||
export function SuiLedgerClientProvider({ | ||
children, | ||
}: SuiLedgerClientProviderProps) { | ||
const [suiLedgerClient, setSuiLedgerClient] = useState<SuiLedgerClient>(); | ||
|
||
useEffect(() => { | ||
const onDisconnect = () => { | ||
setSuiLedgerClient(undefined); | ||
}; | ||
|
||
suiLedgerClient?.transport.on('disconnect', onDisconnect); | ||
return () => suiLedgerClient?.transport.off('disconnect', onDisconnect); | ||
}, [suiLedgerClient?.transport]); | ||
|
||
const connectToLedger = useCallback(async () => { | ||
if (suiLedgerClient?.transport) { | ||
// If we've already connected to a Ledger device, we need | ||
// to close the connection before we try to re-connect | ||
await suiLedgerClient.transport.close(); | ||
} | ||
|
||
const ledgerTransport = await getLedgerTransport(); | ||
const ledgerClient = new SuiLedgerClient(ledgerTransport); | ||
setSuiLedgerClient(ledgerClient); | ||
return ledgerClient; | ||
}, [suiLedgerClient]); | ||
|
||
const contextValue: SuiLedgerClientContextValue = useMemo( | ||
() => [suiLedgerClient, connectToLedger], | ||
[connectToLedger, suiLedgerClient] | ||
); | ||
|
||
return ( | ||
<SuiLedgerClientContext.Provider value={contextValue}> | ||
{children} | ||
</SuiLedgerClientContext.Provider> | ||
); | ||
} | ||
|
||
export function useSuiLedgerClient() { | ||
const suiLedgerClientContext = useContext(SuiLedgerClientContext); | ||
if (!suiLedgerClientContext) { | ||
throw new Error( | ||
'useSuiLedgerClient use must be within SuiLedgerClientContext' | ||
); | ||
} | ||
return suiLedgerClientContext; | ||
} | ||
|
||
async function getLedgerTransport() { | ||
let ledgerTransport: Transport | null | undefined; | ||
|
||
try { | ||
ledgerTransport = await initiateLedgerConnection(); | ||
} catch (error) { | ||
throw new LedgerConnectionFailedError( | ||
"Unable to connect to the user's Ledger device" | ||
); | ||
} | ||
|
||
if (!ledgerTransport) { | ||
throw new LedgerNoTransportMechanismError( | ||
"There are no supported transport mechanisms to connect to the user's Ledger device" | ||
); | ||
} | ||
|
||
return ledgerTransport; | ||
} | ||
|
||
async function initiateLedgerConnection(): Promise<Transport | null> { | ||
if (await TransportWebHID.isSupported()) { | ||
return await TransportWebHID.request(); | ||
} else if (await TransportWebUSB.isSupported()) { | ||
return await TransportWebUSB.request(); | ||
} | ||
return null; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.