@@ -1,55 +1,41 @@
1import * as bip32 from 'bip32';
1import * as bip32 from 'bip32';
2−import React from 'react';
2+import React, { useState } from 'react';
3import Maybe from 'folktale/maybe';
3import Maybe from 'folktale/maybe';
4+import TrezorConnect from 'trezor-connect';
5+import * as secp256k1 from 'secp256k1';
4−import { Button } from '../../components/old/Base';
7+import View from '../../components/View';
5−import { Row, Col, H1, P } from '../../components/old/Base';
8+import { ForwardButton } from '../../components/Buttons';
7 InnerLabel,
12 InnerLabel,
9 InnerLabelDropdown,
14 InnerLabelDropdown,
10} from '../../components/old/Base';
15} from '../../components/old/Base';
11−import TrezorConnect from 'trezor-connect';
12−import * as secp256k1 from 'secp256k1';
14import { TREZOR_PATH } from '../../lib/trezor';
17import { TREZOR_PATH } from '../../lib/trezor';
15−import { compose } from '../../lib/lib';
16−import { withWallet } from '../../store/wallet';
18+import { useWallet } from '../../store/wallet';
18−class Trezor extends React.Component {
22− this.state = {
20+export default function Trezor({ loginCompleted }) {
23− hdpath: TREZOR_PATH.replace(/x/g, 0),
21+ const { wallet, setWallet, setWalletHdPath } = useWallet();
27− this.handleAccountSelection = this.handleAccountSelection.bind(this);
23+ const [hdPath, setHdPath] = useState(TREZOR_PATH.replace(/x/g, 0));
28− this.handleHdPathInput = this.handleHdPathInput.bind(this);
24+ const [account, setAccount] = useState(0);
29− this.pollDevice = this.pollDevice.bind(this);
32− handleAccountSelection(account) {
26+ const handleAccountSelection = account => {
33− let hdpath = this.state.hdpath;
27+ setAccount(account);
34 if (account !== 'custom') {
28 if (account !== 'custom') {
35− hdpath = TREZOR_PATH.replace(/x/g, account);
29+ setHdPath(TREZOR_PATH.replace(/x/g, account));
37− this.setState({ account, hdpath });
40− handleHdPathInput(hdpath) {
41− this.setState({ hdpath });
45− const { setWallet, setWalletHdPath } = this.props;
46− const { hdpath } = this.state;
33+ const pollDevice = async () => {
48 TrezorConnect.manifest({
34 TrezorConnect.manifest({
49 email: 'bridge-trezor@urbit.org',
35 email: 'bridge-trezor@urbit.org',
50 appUrl: 'https://github.com/urbit/bridge',
36 appUrl: 'https://github.com/urbit/bridge',
52− TrezorConnect.getPublicKey({ path: hdpath }).then(info => {
38+ TrezorConnect.getPublicKey({ path: hdPath }).then(info => {
53 if (info.success === true) {
39 if (info.success === true) {
54 const payload = info.payload;
40 const payload = info.payload;
55 const publicKey = Buffer.from(payload.publicKey, 'hex');
41 const publicKey = Buffer.from(payload.publicKey, 'hex');
@@ -57,90 +43,76 @@ class Trezor extends React.Component {
57 const pub = secp256k1.publicKeyConvert(publicKey, true);
43 const pub = secp256k1.publicKeyConvert(publicKey, true);
58 const hd = bip32.fromPublicKey(pub, chainCode);
44 const hd = bip32.fromPublicKey(pub, chainCode);
59 setWallet(Maybe.Just(hd));
45 setWallet(Maybe.Just(hd));
60− setWalletHdPath(hdpath);
46+ setWalletHdPath(hdPath);
62 setWallet(Maybe.Nothing());
48 setWallet(Maybe.Nothing());
53+ let accountOptions = [
55+ title: 'Custom path',
59+ for (let i = 0; i < 20; i++) {
60+ accountOptions.push({
61+ title: 'Account #' + (i + 1),
68− const { wallet } = this.props;
69− const { hdpath, account } = this.state;
70− const { handleAccountSelection } = this;
72− let accountOptions = [
74− title: 'Custom path',
78− for (let i = 0; i < 20; i++) {
79− accountOptions.push({
80− title: 'Account #' + (i + 1),
84− let accountTitle = accountOptions.find(o => o.value === account).title;
65+ let accountTitle = accountOptions.find(o => o.value === account).title;
86− const accountSelection = (
67+ const accountSelection = (
87− <InnerLabelDropdown
68+ <InnerLabelDropdown
71+ prop-format="innerLabel"
72+ options={accountOptions}
73+ handleUpdate={handleAccountSelection}
75+ currentSelectionTitle={accountTitle}
80+ const pathSelection =
81+ account !== 'custom' ? null : (
88− className="mt-8"
83+ className="mt-8 pt-8 text-mono"
89 prop-size="md"
84 prop-size="md"
90 prop-format="innerLabel"
85 prop-format="innerLabel"
91− options={accountOptions}
86+ name="hdPath"
92− handleUpdate={handleAccountSelection}
87+ value={hdPath}
93− title={'Account'}
88+ autocomplete="off"
94− currentSelectionTitle={accountTitle}
89+ onChange={setHdPath}>
95− fullWidth={true}
90+ <InnerLabel>{'HD Path'}</InnerLabel>
99− const pathSelection =
100− account !== 'custom' ? null : (
102− className="mt-8 pt-8 text-mono"
104− prop-format="innerLabel"
108− onChange={this.handleHdPathInput}>
109− <InnerLabel>{'HD Path'}</InnerLabel>
113− return (
94+ return (
115− <Col className={'measure-md'}>
116− <H1>{'Authenticate With Your Trezor'}</H1>
96+ <H1>{'Authenticate With Your Trezor'}</H1>
119− {`Connect and authenticate to your Trezor. If you'd like
99+ {`Connect and authenticate to your Trezor. If you'd like
120− to use a custom derivation path, you may enter it below.`}
100+ to use a custom derivation path, you may enter it below.`}
123− {accountSelection}
103+ {accountSelection}
124− {pathSelection}
104+ {pathSelection}
128− prop-size={'wide lg'}
129− onClick={this.pollDevice}>
106+ <ForwardButton className={'mt3'} onClick={pollDevice}>
130− {'Authenticate →'}
107+ {'Authenticate'}
131− </Button>
108+ </ForwardButton>
133− <Button
110+ <ForwardButton
134− className={'mt-8'}
111+ className={'mt3'}
135− prop-size={'wide lg'}
136− disabled={Maybe.Nothing.hasInstance(wallet)}
112+ disabled={Maybe.Nothing.hasInstance(wallet)}
137− onClick={this.props.loginCompleted}>
113+ onClick={loginCompleted}>
138− {'Continue →'}
114+ {'Continue'}
139− </Button>
115+ </ForwardButton>
146−export default compose(withWallet)(Trezor);