1import * as bip32 from 'bip32';
2import React from 'react';
3import Maybe from 'folktale/maybe';
4import { Button } from '../components/old/Base';
5import { H1, P, H2 } from '../components/old/Base';
6import { Input, InnerLabel, InnerLabelDropdown } from '../components/old/Base';
7import Transport from '@ledgerhq/hw-transport-u2f';
8import Eth from '@ledgerhq/hw-app-eth';
9import * as secp256k1 from 'secp256k1';
11import { LEDGER_LIVE_PATH, LEDGER_LEGACY_PATH } from '../lib/ledger';
12import { ROUTE_NAMES } from '../lib/routeNames';
13import { withHistory } from '../store/history';
14import { compose } from '../lib/lib';
15import { withWallet } from '../store/wallet';
16import View from 'components/View';
18const chopHdPrefix = str => (str.slice(0, 2) === 'm/' ? str.slice(2) : str);
20const addHdPrefix = str => (str.slice(0, 2) === 'm/' ? str : 'm/' + str);
22class Ledger extends React.Component {
27 basePath: LEDGER_LIVE_PATH,
28 hdpath: LEDGER_LIVE_PATH.replace(/x/g, 0),
32 this.pollDevice = this.pollDevice.bind(this);
33 this.handleHdPathInput = this.handleHdPathInput.bind(this);
34 this.handlePathSelection = this.handlePathSelection.bind(this);
35 this.handleAccountSelection = this.handleAccountSelection.bind(this);
36 this.updateHdPath = this.updateHdPath.bind(this);
39 handlePathSelection(basePath) {
40 this.updateHdPath(basePath, this.state.account);
43 handleAccountSelection(account) {
44 this.updateHdPath(this.state.basePath, account);
47 updateHdPath(basePath, account) {
48 let hdpath = this.state.hdpath;
49 if (basePath !== 'custom') {
50 hdpath = basePath.replace(/x/g, account);
52 this.setState({ basePath, account, hdpath });
55 handleHdPathInput(hdpath) {
56 this.setState({ hdpath });
60 const { setWallet, setWalletHdPath } = this.props;
61 const { hdpath } = this.state;
63 const transport = await Transport.create();
64 const eth = new Eth(transport);
65 const path = chopHdPrefix(hdpath);
67 eth.getAddress(path, false, true).then(
69 const publicKey = Buffer.from(info.publicKey, 'hex');
70 const chainCode = Buffer.from(info.chainCode, 'hex');
71 const pub = secp256k1.publicKeyConvert(publicKey, true);
72 const hd = bip32.fromPublicKey(pub, chainCode);
73 setWallet(Maybe.Just(hd));
74 setWalletHdPath(addHdPrefix(hdpath));
77 setWallet(Maybe.Nothing());
83 const { history, wallet } = this.props;
84 const { basePath, hdpath, account } = this.state;
85 const { handlePathSelection, handleAccountSelection } = this;
88 { title: 'Ledger Live', value: LEDGER_LIVE_PATH },
89 { title: 'Ledger Legacy', value: LEDGER_LEGACY_PATH },
95 let basePathTitle = pathOptions.find(o => o.value === basePath).title;
97 let accountOptions = [];
98 for (let i = 0; i < 20; i++) {
100 title: 'Account #' + (i + 1),
104 let accountTitle = accountOptions.find(o => o.value === account).title;
106 const basePathSelection = (
109 options={pathOptions}
110 handleUpdate={handlePathSelection}
111 title={'Derivation path'}
112 currentSelectionTitle={basePathTitle}
117 const truePathSelection =
118 basePath === 'custom' ? (
120 className="pt-8 mt-4 text-mono"
122 prop-format="innerLabel"
124 value={addHdPrefix(hdpath)}
126 onChange={this.handleHdPathInput}>
127 <InnerLabel>{'HD Path'}</InnerLabel>
133 prop-format="innerLabel"
134 options={accountOptions}
135 handleUpdate={handleAccountSelection}
137 currentSelectionTitle={accountTitle}
144 <H1>{'Authenticate With Your Ledger'}</H1>
146 <H2>{'Running on HTTPS?'}</H2>
149 {`Connect and authenticate to your Ledger, and then open the
150 "Ethereum" application. If you're running on older firmware,
151 make sure the "browser support" option is turned on. To sign
152 transactions, you'll also need to enable the "contract data"
157 {`If you'd like to use a custom derivation path, you may enter
161 <H2>{'Running on HTTP?'}</H2>
163 <P>{`To authenticate and sign transactions with a Ledger, Bridge
164 must be serving over HTTPS on localhost. You can do this via the
167 <ol className={'measure-md'}>
168 <li className={'mt-4'}>
170 <a target={'_blank'} href={'https://github.com/FiloSottile/mkcert'}>
174 <li className={'mt-4'}>
175 {'Install a local certificate authority via '}
176 <code>{'mkcert -install'}</code>
178 <li className={'mt-4'}>
180 <code>{'bridge'}</code>
181 {' directory, generate a certificate valid for localhost via '}{' '}
182 <code>{'mkcert localhost'}</code>
184 {'This will produce two files: '}
185 <code>{'localhost.pem'}</code> {', the local certificate, and '}
186 <code>{'localhost-key.pem'}</code>
187 {', its corresponding private key.'}
189 <li className={'mt-4'}>
191 <code>{'python bridge-https.py'}</code>
199 prop-size={'wide lg'}
201 onClick={this.pollDevice}>
207 prop-size={'wide lg'}
208 disabled={Maybe.Nothing.hasInstance(wallet)}
209 onClick={() => history.popAndPush(ROUTE_NAMES.POINTS)}>
217export default compose(
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