on d760cbf help sign in
bridge/src/views/Login/Trezor.js
125 lines 3.2 kB history raw
1import React, { useEffect } from 'react';
2import { Just, Nothing } from 'folktale/maybe';
3import * as bip32 from 'bip32';
4import { times } from 'lodash';
5import TrezorConnect from 'trezor-connect';
6import * as secp256k1 from 'secp256k1';
7import {
8 Text,
9 Input,
10 Grid,
11 H5,
12 CheckboxInput,
13 SelectInput,
14} from 'indigo-react';
16import { useWallet } from 'store/wallet';
18import { TREZOR_PATH } from 'lib/trezor';
19import { WALLET_TYPES } from 'lib/wallet';
20import useLoginView from 'lib/useLoginView';
21import {
22 useHdPathInput,
23 useCheckboxInput,
24 useSelectInput,
25} from 'lib/useInputs';
27import { ForwardButton } from 'components/Buttons';
29const ACCOUNT_OPTIONS = times(20, i => ({
30 text: `Account #${i + 1}`,
31 value: i,
32}));
34// see Ledger.js for context — Trezor is basicaly Ledger with less complexity
35export default function Trezor({ className }) {
36 useLoginView(WALLET_TYPES.TREZOR);
38 const { setWallet, setWalletHdPath } = useWallet();
40 // custom toggle
41 const [customPathInput, { data: useCustomPath }] = useCheckboxInput({
42 name: 'customPath',
43 label: 'Custom HD Path',
44 autoComplete: 'off',
45 initialValue: false,
46 });
48 // account input
49 const [accountInput, { data: accountIndex }] = useSelectInput({
50 name: 'account',
51 label: 'Account',
52 placeholder: 'Choose account...',
53 options: ACCOUNT_OPTIONS,
54 });
56 // hd path input
57 const [
58 hdPathInput,
59 { data: hdPath },
60 { setValue: setHdPath },
61 ] = useHdPathInput({
62 name: 'hdpath',
63 label: 'HD Path',
64 initialValue: TREZOR_PATH.replace(/x/g, 0),
65 });
67 const pollDevice = async () => {
68 TrezorConnect.manifest({
69 email: 'bridge-trezor@urbit.org',
70 appUrl: 'https://github.com/urbit/bridge',
71 });
73 const info = await TrezorConnect.getPublicKey({
74 path: hdPath,
75 });
77 if (info.success === true) {
78 const payload = info.payload;
79 const publicKey = Buffer.from(payload.publicKey, 'hex');
80 const chainCode = Buffer.from(payload.chainCode, 'hex');
81 const pub = secp256k1.publicKeyConvert(publicKey, true);
82 const hd = bip32.fromPublicKey(pub, chainCode);
83 setWallet(Just(hd));
84 setWalletHdPath(hdPath);
85 } else {
86 setWallet(Nothing());
87 }
88 };
90 useEffect(() => {
91 if (useCustomPath) {
92 // updated by useForm
93 } else {
94 setHdPath(TREZOR_PATH.replace(/x/g, accountIndex));
95 }
96 }, [useCustomPath, setHdPath, accountIndex]);
98 return (
99 <Grid className={className}>
100 <Grid.Item full as={H5}>
101 Authenticate With Your Trezor
102 </Grid.Item>
104 <Grid.Item full as={Text} className="f6 mb3">
105 Connect and authenticate to your Trezor. If you'd like to use a custom
106 derivation path, you may enter it below.
107 </Grid.Item>
109 {useCustomPath && <Grid.Item full as={Input} {...hdPathInput} />}
111 {!useCustomPath && <Grid.Item full as={SelectInput} {...accountInput} />}
113 <Grid.Item full as={CheckboxInput} className="mv3" {...customPathInput} />
115 <Grid.Item
116 full
117 as={ForwardButton}
118 solid
119 className="mt2"
120 onClick={pollDevice}>
121 Authenticate
122 </Grid.Item>
123 </Grid>
124 );