1import React, { useCallback, useMemo } from 'react';
2import { Just } from 'folktale/maybe';
3import * as bip32 from 'bip32';
4import { times } from 'lodash';
5import TrezorConnect from 'trezor-connect';
6import * as secp256k1 from 'secp256k1';
7import { Text, Grid, H5, CheckboxInput, SelectInput } from 'indigo-react';
9import { useWallet } from 'store/wallet';
11import { TREZOR_PATH } from 'lib/trezor';
12import { WALLET_TYPES } from 'lib/wallet';
13import useLoginView from 'lib/useLoginView';
14import { getAuthToken } from 'lib/authToken';
18 buildCheckboxValidator,
21} from 'form/validators';
22import BridgeForm from 'form/BridgeForm';
23import Condition from 'form/Condition';
24import FormError from 'form/FormError';
26import SubmitButton from 'form/SubmitButton';
27import { FORM_ERROR } from 'final-form';
28import { HdPathInput } from 'form/Inputs';
30const ACCOUNT_OPTIONS = times(20, i => ({
31 text: `Account #${i + 1}`,
35// see Ledger.js for context — Trezor is basicaly Ledger with less complexity
36export default function Trezor({ className, goHome }) {
37 useLoginView(WALLET_TYPES.TREZOR);
39 const { setWallet, setWalletHdPath, setAuthToken } = useWallet();
41 const validate = useMemo(
44 useCustomPath: buildCheckboxValidator(),
45 account: buildSelectValidator(ACCOUNT_OPTIONS),
46 hdPath: buildHdPathValidator(),
51 const onSubmit = useCallback(
53 TrezorConnect.manifest({
54 email: 'bridge-trezor@urbit.org',
55 appUrl: 'https://github.com/urbit/bridge',
58 const { success, payload } = await TrezorConnect.getPublicKey({
63 return { [FORM_ERROR]: 'Failed to authenticate with your Trezor.' };
66 const publicKey = Buffer.from(payload.publicKey, 'hex');
67 const chainCode = Buffer.from(payload.chainCode, 'hex');
68 const pub = secp256k1.publicKeyConvert(publicKey, true);
69 const hd = bip32.fromPublicKey(pub, chainCode);
71 const authToken = await getAuthToken({
73 walletType: WALLET_TYPES.TREZOR,
74 walletHdPath: values.hdPath,
77 setAuthToken(Just(authToken));
79 setWalletHdPath(values.hdPath);
81 [setAuthToken, setWallet, setWalletHdPath]
84 const onValues = useCallback(({ valid, values, form }) => {
89 if (!values.useCustomPath) {
90 form.change('hdPath', TREZOR_PATH.replace(/x/g, values.account));
94 const initialValues = useMemo(
97 hdPath: TREZOR_PATH.replace(/x/g, ACCOUNT_OPTIONS[0].value),
98 account: ACCOUNT_OPTIONS[0].value,
104 <Grid className={className}>
105 <Grid.Item full as={Text} className="f6 gray4 mb3">
106 Connect and authenticate to your Trezor. If you'd like to use a custom
107 derivation path, you may enter it below. Upon login, you will prompted
108 to sign the message "Bridge Authentication Token". This allows Bridge to
109 operate correctly. Never sign this message outside of Bridge.
117 initialValues={initialValues}>
118 {({ handleSubmit, submitting }) => (
120 <Condition when="useCustomPath" is={true}>
121 <Grid.Item full as={HdPathInput} name="hdPath" label="HD Path" />
124 <Condition when="useCustomPath" is={false}>
130 placeholder="Choose account..."
131 options={ACCOUNT_OPTIONS}
140 label="Custom HD Path"
143 <Grid.Item full as={FormError} />
145 <Grid.Item full as={SubmitButton} handleSubmit={handleSubmit}>
146 {!submitting && 'Authenticate'}
147 {submitting && 'Please check your device'}
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list