Implement the address derivations

This commit is contained in:
Leonid Logvinov
2017-12-18 12:30:34 +01:00
parent 6d447fd8a5
commit 064405126d
4 changed files with 32 additions and 17 deletions

View File

@@ -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<ECSignatureString>;
public getAppConfiguration_async(): Promise<{ arbitraryDataEnabled: number; version: string }>;
public signPersonalMessage_async(path: string, messageHex: string): Promise<ECSignature>;

View File

@@ -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<string[]> {
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<string> {

View File

@@ -11,7 +11,7 @@ export interface LedgerCommunicationClient {
*/
export interface LedgerEthereumClient {
getAddress_async: (derivationPath: string, askForDeviceConfirmation: boolean,
shouldGetChainCode: boolean) => Promise<LedgerGetAddressResult>;
shouldGetChainCode: true) => Promise<LedgerGetAddressResult>;
signPersonalMessage_async: (derivationPath: string, messageHex: string) => Promise<ECSignature>;
signTransaction_async: (derivationPath: string, txHex: string) => Promise<ECSignatureString>;
comm: LedgerCommunicationClient;
@@ -63,6 +63,8 @@ export interface SignatureData {
export interface LedgerGetAddressResult {
address: string;
publicKey: string;
chainCode: string;
}
export interface LedgerWalletSubprovider {

View File

@@ -18,7 +18,7 @@ import {reportCallbackErrors} from '../utils/report_callback_errors';
chaiSetup.configure();
const expect = chai.expect;
const FAKE_ADDRESS = '0x9901c66f2d4b95f7074b553da78084d708beca70';
const FAKE_ADDRESS = '0xb088a3bc93f71b4de97b9de773e9647645983688';
describe('LedgerSubprovider', () => {
const networkId: number = 42;
@@ -28,8 +28,14 @@ describe('LedgerSubprovider', () => {
// tslint:disable:no-object-literal-type-assertion
const ledgerEthClient = {
getAddress_async: async () => {
// tslint:disable-next-line:max-line-length
const publicKey = '04f428290f4c5ed6a198f71b8205f488141dbb3f0840c923bbfa798ecbee6370986c03b5575d94d506772fb48a6a44e345e4ebd4f028a6f609c44b655d6d3e71a1';
const chainCode = 'ac055a5537c0c7e9e02d14a197cad6b857836da2a12043b46912a37d959b5ae8';
const address = '0xBa388BA5e5EEF2c6cE42d831c2B3A28D3c99bdB1';
return {
address: FAKE_ADDRESS,
publicKey,
address,
chainCode,
};
},
signPersonalMessage_async: async () => {