From 6d447fd8a509118dca4f52c4939782e67f4f1076 Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Mon, 18 Dec 2017 12:30:14 +0100 Subject: Add hdnode dependency --- packages/subproviders/src/globals.d.ts | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'packages/subproviders/src') diff --git a/packages/subproviders/src/globals.d.ts b/packages/subproviders/src/globals.d.ts index adef23806..ce7b46155 100644 --- a/packages/subproviders/src/globals.d.ts +++ b/packages/subproviders/src/globals.d.ts @@ -91,3 +91,14 @@ declare module 'web3-provider-engine' { } export = Web3ProviderEngine; } + +// hdkey declarations +declare module 'hdkey' { + class HDNode { + public publicKey: Buffer; + public chainCode: Buffer; + public constructor(); + public derive(path: string): HDNode; + } + export = HDNode; +} -- cgit v1.2.3 From 064405126d7e198c6c3363416abf3b1bc16acc6a Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Mon, 18 Dec 2017 12:30:34 +0100 Subject: Implement the address derivations --- packages/subproviders/src/globals.d.ts | 2 +- packages/subproviders/src/subproviders/ledger.ts | 33 ++++++++++++++---------- packages/subproviders/src/types.ts | 4 ++- 3 files changed, 24 insertions(+), 15 deletions(-) (limited to 'packages/subproviders/src') diff --git a/packages/subproviders/src/globals.d.ts b/packages/subproviders/src/globals.d.ts index ce7b46155..3800c970f 100644 --- a/packages/subproviders/src/globals.d.ts +++ b/packages/subproviders/src/globals.d.ts @@ -48,7 +48,7 @@ declare module 'ledgerco' { public comm: comm; constructor(comm: comm); public getAddress_async(path: string, display?: boolean, chaincode?: boolean): - Promise<{publicKey: string; address: string}>; + Promise<{publicKey: string; address: string; chainCode: string}>; public signTransaction_async(path: string, rawTxHex: string): Promise; public getAppConfiguration_async(): Promise<{ arbitraryDataEnabled: number; version: string }>; public signPersonalMessage_async(path: string, messageHex: string): Promise; diff --git a/packages/subproviders/src/subproviders/ledger.ts b/packages/subproviders/src/subproviders/ledger.ts index 9ffc105a4..9b2f1d129 100644 --- a/packages/subproviders/src/subproviders/ledger.ts +++ b/packages/subproviders/src/subproviders/ledger.ts @@ -2,6 +2,7 @@ import {assert} from '@0xproject/assert'; import {addressUtils} from '@0xproject/utils'; import EthereumTx = require('ethereumjs-tx'); import ethUtil = require('ethereumjs-util'); +import HDNode = require('hdkey'); import * as _ from 'lodash'; import Semaphore from 'semaphore-async-await'; import Web3 = require('web3'); @@ -20,7 +21,7 @@ import {Subprovider} from './subprovider'; const DEFAULT_DERIVATION_PATH = `44'/60'/0'`; const NUM_ADDRESSES_TO_FETCH = 10; const ASK_FOR_ON_DEVICE_CONFIRMATION = false; -const SHOULD_GET_CHAIN_CODE = false; +const SHOULD_GET_CHAIN_CODE = true; export class LedgerSubprovider extends Subprovider { private _nonceLock: Semaphore; @@ -127,21 +128,27 @@ export class LedgerSubprovider extends Subprovider { public async getAccountsAsync(): Promise { this._ledgerClientIfExists = await this.createLedgerClientAsync(); - // TODO: replace with generating addresses without hitting Ledger + let ledgerResponse; + try { + ledgerResponse = await this._ledgerClientIfExists.getAddress_async( + `${this._derivationPath}`, this._shouldAlwaysAskForConfirmation, SHOULD_GET_CHAIN_CODE, + ); + } finally { + await this.destoryLedgerClientAsync(); + } + + const hdKey = new HDNode(); + hdKey.publicKey = new Buffer(ledgerResponse.publicKey, 'hex'); + hdKey.chainCode = new Buffer(ledgerResponse.chainCode, 'hex'); + const accounts = []; for (let i = 0; i < NUM_ADDRESSES_TO_FETCH; i++) { - try { - const derivationPath = `${this._derivationPath}/${i + this._derivationPathIndex}`; - const result = await this._ledgerClientIfExists.getAddress_async( - derivationPath, this._shouldAlwaysAskForConfirmation, SHOULD_GET_CHAIN_CODE, - ); - accounts.push(result.address.toLowerCase()); - } catch (err) { - await this.destoryLedgerClientAsync(); - throw err; - } + const derivedHDNode = hdKey.derive(`m/${i + this._derivationPathIndex}`); + const derivedPublicKey = derivedHDNode.publicKey; + const ethereumAddressUnprefixed = ethUtil.publicToAddress(derivedPublicKey, true).toString('hex'); + const ethereumAddressPrefixed = ethUtil.addHexPrefix(ethereumAddressUnprefixed); + accounts.push(ethereumAddressPrefixed.toLowerCase()); } - await this.destoryLedgerClientAsync(); return accounts; } public async signTransactionAsync(txParams: PartialTxParams): Promise { diff --git a/packages/subproviders/src/types.ts b/packages/subproviders/src/types.ts index 1e7d3eab0..02855dd4c 100644 --- a/packages/subproviders/src/types.ts +++ b/packages/subproviders/src/types.ts @@ -11,7 +11,7 @@ export interface LedgerCommunicationClient { */ export interface LedgerEthereumClient { getAddress_async: (derivationPath: string, askForDeviceConfirmation: boolean, - shouldGetChainCode: boolean) => Promise; + shouldGetChainCode: true) => Promise; signPersonalMessage_async: (derivationPath: string, messageHex: string) => Promise; signTransaction_async: (derivationPath: string, txHex: string) => Promise; comm: LedgerCommunicationClient; @@ -63,6 +63,8 @@ export interface SignatureData { export interface LedgerGetAddressResult { address: string; + publicKey: string; + chainCode: string; } export interface LedgerWalletSubprovider { -- cgit v1.2.3 From 950406f1f9ad79a60ced5f6680c33fbc4237de3b Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Mon, 18 Dec 2017 14:47:39 +0100 Subject: Remove redundant template string --- packages/subproviders/src/subproviders/ledger.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'packages/subproviders/src') diff --git a/packages/subproviders/src/subproviders/ledger.ts b/packages/subproviders/src/subproviders/ledger.ts index 9b2f1d129..793effaeb 100644 --- a/packages/subproviders/src/subproviders/ledger.ts +++ b/packages/subproviders/src/subproviders/ledger.ts @@ -131,7 +131,7 @@ export class LedgerSubprovider extends Subprovider { let ledgerResponse; try { ledgerResponse = await this._ledgerClientIfExists.getAddress_async( - `${this._derivationPath}`, this._shouldAlwaysAskForConfirmation, SHOULD_GET_CHAIN_CODE, + this._derivationPath, this._shouldAlwaysAskForConfirmation, SHOULD_GET_CHAIN_CODE, ); } finally { await this.destoryLedgerClientAsync(); -- cgit v1.2.3 From 90d1c3e2c98944728ac9d38f22c050a490318deb Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Mon, 18 Dec 2017 14:49:13 +0100 Subject: Introduce a variable for true --- packages/subproviders/src/subproviders/ledger.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'packages/subproviders/src') diff --git a/packages/subproviders/src/subproviders/ledger.ts b/packages/subproviders/src/subproviders/ledger.ts index 793effaeb..f9922fdda 100644 --- a/packages/subproviders/src/subproviders/ledger.ts +++ b/packages/subproviders/src/subproviders/ledger.ts @@ -145,7 +145,10 @@ export class LedgerSubprovider extends Subprovider { for (let i = 0; i < NUM_ADDRESSES_TO_FETCH; i++) { const derivedHDNode = hdKey.derive(`m/${i + this._derivationPathIndex}`); const derivedPublicKey = derivedHDNode.publicKey; - const ethereumAddressUnprefixed = ethUtil.publicToAddress(derivedPublicKey, true).toString('hex'); + const shouldSanitizePublicKey = true; + const ethereumAddressUnprefixed = ethUtil.publicToAddress( + derivedPublicKey, shouldSanitizePublicKey, + ).toString('hex'); const ethereumAddressPrefixed = ethUtil.addHexPrefix(ethereumAddressUnprefixed); accounts.push(ethereumAddressPrefixed.toLowerCase()); } -- cgit v1.2.3 From a3a2df098b3a67ec2da036ae469cb54709f0fd71 Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Mon, 18 Dec 2017 15:56:31 +0100 Subject: Add a comment --- packages/subproviders/src/types.ts | 2 ++ 1 file changed, 2 insertions(+) (limited to 'packages/subproviders/src') diff --git a/packages/subproviders/src/types.ts b/packages/subproviders/src/types.ts index 02855dd4c..c5ccf1fda 100644 --- a/packages/subproviders/src/types.ts +++ b/packages/subproviders/src/types.ts @@ -10,6 +10,8 @@ export interface LedgerCommunicationClient { * NodeJs and Browser communication are supported. */ export interface LedgerEthereumClient { + // shouldGetChainCode is defined as `true` instead of `boolean` because other types rely on the assumption + // that we get back the chain code and we don't have dependent types to express it properly getAddress_async: (derivationPath: string, askForDeviceConfirmation: boolean, shouldGetChainCode: true) => Promise; signPersonalMessage_async: (derivationPath: string, messageHex: string) => Promise; -- cgit v1.2.3