1import * as bip32 from 'bip32';
2import React from 'react';
3import Maybe from 'folktale/maybe';
4import { Button } from '../components/old/Base';
5import { Row, Col, 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';
17const chopHdPrefix = str => (str.slice(0, 2) === 'm/' ? str.slice(2) : str);
19const addHdPrefix = str => (str.slice(0, 2) === 'm/' ? str : 'm/' + str);
21class Ledger extends React.Component {
26 basePath: LEDGER_LIVE_PATH,
27 hdpath: LEDGER_LIVE_PATH.replace(/x/g, 0),
31 this.pollDevice = this.pollDevice.bind(this);
32 this.handleHdPathInput = this.handleHdPathInput.bind(this);
33 this.handlePathSelection = this.handlePathSelection.bind(this);
34 this.handleAccountSelection = this.handleAccountSelection.bind(this);
35 this.updateHdPath = this.updateHdPath.bind(this);
38 handlePathSelection(basePath) {
39 this.updateHdPath(basePath, this.state.account);
42 handleAccountSelection(account) {
43 this.updateHdPath(this.state.basePath, account);
46 updateHdPath(basePath, account) {
47 let hdpath = this.state.hdpath;
48 if (basePath !== 'custom') {
49 hdpath = basePath.replace(/x/g, account);
51 this.setState({ basePath, account, hdpath });
54 handleHdPathInput(hdpath) {
55 this.setState({ hdpath });
59 const { setWallet, setWalletHdPath } = this.props;
60 const { hdpath } = this.state;
62 const transport = await Transport.create();
63 const eth = new Eth(transport);
64 const path = chopHdPrefix(hdpath);
66 eth.getAddress(path, false, true).then(
68 const publicKey = Buffer.from(info.publicKey, 'hex');
69 const chainCode = Buffer.from(info.chainCode, 'hex');
70 const pub = secp256k1.publicKeyConvert(publicKey, true);
71 const hd = bip32.fromPublicKey(pub, chainCode);
72 setWallet(Maybe.Just(hd));
73 setWalletHdPath(addHdPrefix(hdpath));
76 setWallet(Maybe.Nothing());
82 const { history, wallet } = this.props;
83 const { basePath, hdpath, account } = this.state;
84 const { handlePathSelection, handleAccountSelection } = this;
87 { title: 'Ledger Live', value: LEDGER_LIVE_PATH },
88 { title: 'Ledger Legacy', value: LEDGER_LEGACY_PATH },
94 let basePathTitle = pathOptions.find(o => o.value === basePath).title;
96 let accountOptions = [];
97 for (let i = 0; i < 20; i++) {
99 title: 'Account #' + (i + 1),
103 let accountTitle = accountOptions.find(o => o.value === account).title;
105 const basePathSelection = (
108 options={pathOptions}
109 handleUpdate={handlePathSelection}
110 title={'Derivation path'}
111 currentSelectionTitle={basePathTitle}
116 const truePathSelection =
117 basePath === 'custom' ? (
119 className="pt-8 mt-4 text-mono"
121 prop-format="innerLabel"
123 value={addHdPrefix(hdpath)}
125 onChange={this.handleHdPathInput}>
126 <InnerLabel>{'HD Path'}</InnerLabel>
132 prop-format="innerLabel"
133 options={accountOptions}
134 handleUpdate={handleAccountSelection}
136 currentSelectionTitle={accountTitle}
143 <Col className={'measure-md'}>
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'}>
172 href={'https://github.com/FiloSottile/mkcert'}>
176 <li className={'mt-4'}>
177 {'Install a local certificate authority via '}
178 <code>{'mkcert -install'}</code>
180 <li className={'mt-4'}>
182 <code>{'bridge'}</code>
184 ' directory, generate a certificate valid for localhost via '
186 <code>{'mkcert localhost'}</code>
188 {'This will produce two files: '}
189 <code>{'localhost.pem'}</code> {', the local certificate, and '}
190 <code>{'localhost-key.pem'}</code>
191 {', its corresponding private key.'}
193 <li className={'mt-4'}>
195 <code>{'python bridge-https.py'}</code>
203 prop-size={'wide lg'}
205 onClick={this.pollDevice}>
211 prop-size={'wide lg'}
212 disabled={Maybe.Nothing.hasInstance(wallet)}
213 onClick={() => history.popAndPush(ROUTE_NAMES.SHIPS)}>
222export 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