diff options
author | Fabio Berger <me@fabioberger.com> | 2017-12-08 01:42:50 +0800 |
---|---|---|
committer | Fabio Berger <me@fabioberger.com> | 2017-12-08 01:42:50 +0800 |
commit | 215e33fa6c1ca3c27712f5253daeaebf590f8983 (patch) | |
tree | cfee907308158726196d4edfebd7a9bc7064e76b | |
parent | 3d12b84f1d1ecf8eb6fa145f4bf124f0b7b484c1 (diff) | |
parent | be17b75ad3e043df6f4ff05ead0627cb9a45d93b (diff) | |
download | dexon-0x-contracts-215e33fa6c1ca3c27712f5253daeaebf590f8983.tar dexon-0x-contracts-215e33fa6c1ca3c27712f5253daeaebf590f8983.tar.gz dexon-0x-contracts-215e33fa6c1ca3c27712f5253daeaebf590f8983.tar.bz2 dexon-0x-contracts-215e33fa6c1ca3c27712f5253daeaebf590f8983.tar.lz dexon-0x-contracts-215e33fa6c1ca3c27712f5253daeaebf590f8983.tar.xz dexon-0x-contracts-215e33fa6c1ca3c27712f5253daeaebf590f8983.tar.zst dexon-0x-contracts-215e33fa6c1ca3c27712f5253daeaebf590f8983.zip |
Merge branch 'feature/addSubproviders' into feature/portal-ledger-support
* feature/addSubproviders:
remove unneeded reset
Use rejectedWith
Add missing calls to configure
remove unneeded type assertions
remove unused type
Simplify interface to signPersonalMessageAsync
Fix unit test
Fix ethereumjs-tx declaration and import
Use assert.isHexString
Add type defs for ledgerco and ethereumjs-tx
Make test only run unit tests since cannot run integration tests on CI
Improve README
Fix version and remove the UMD build
Fix tslint error
-rw-r--r-- | packages/subproviders/README.md | 2 | ||||
-rw-r--r-- | packages/subproviders/package.json | 17 | ||||
-rw-r--r-- | packages/subproviders/src/globals.d.ts | 48 | ||||
-rw-r--r-- | packages/subproviders/src/subproviders/ledger.ts | 37 | ||||
-rw-r--r-- | packages/subproviders/src/types.ts | 7 | ||||
-rw-r--r-- | packages/subproviders/test/integration/ledger_subprovider_test.ts | 3 | ||||
-rw-r--r-- | packages/subproviders/test/unit/ledger_subprovider_test.ts | 39 | ||||
-rw-r--r-- | packages/subproviders/webpack.config.js | 56 | ||||
-rw-r--r-- | packages/website/package.json | 2 | ||||
-rw-r--r-- | packages/website/ts/components/ui/lifecycle_raised_button.tsx | 2 | ||||
-rw-r--r-- | packages/website/ts/globals.d.ts | 2 |
11 files changed, 68 insertions, 147 deletions
diff --git a/packages/subproviders/README.md b/packages/subproviders/README.md index 72f18a962..5fa31611a 100644 --- a/packages/subproviders/README.md +++ b/packages/subproviders/README.md @@ -29,7 +29,7 @@ In order to run the integration tests, make sure you have a Ledger Nano S availa - Plug it into your computer - Unlock the device -- Open the Ethereum app +- Open the on-device Ethereum app - Make sure "browser support" is disabled Then run: diff --git a/packages/subproviders/package.json b/packages/subproviders/package.json index 74d1ba8c9..11d116278 100644 --- a/packages/subproviders/package.json +++ b/packages/subproviders/package.json @@ -1,25 +1,20 @@ { "name": "@0xproject/subproviders", - "version": "0.0.0", + "version": "0.0.1", "main": "lib/src/index.js", "types": "lib/src/index.d.ts", "license": "Apache-2.0", "scripts": { "prebuild": "npm run clean", - "build": "run-p build:umd:dev build:commonjs; exit 0;", "clean": "shx rm -rf lib", - "build:umd:dev": "webpack", - "build:umd:prod": "NODE_ENV=production webpack", - "build:commonjs": "tsc", + "build": "tsc", "lint": "tslint --project . 'src/**/*.ts' 'test/**/*.ts'", - "pretest:umd": "run-s clean build:umd:dev build:commonjs", - "substitute_umd_bundle": "shx mv _bundles/* lib/src", - "run_mocha_all": "mocha lib/test/**/*_test.js --timeout 10000 --bail --exit", "run_mocha_unit": "mocha lib/test/unit/**/*_test.js --timeout 10000 --bail --exit", "run_mocha_integration": "mocha lib/test/integration/**/*_test.js --timeout 10000 --bail --exit", - "test": "run-s clean build:commonjs run_mocha_all", - "test:unit": "run-s clean build:commonjs run_mocha_unit", - "test:integration": "run-s clean build:commonjs run_mocha_integration" + "test": "npm run test:unit", + "test:all": "run-s test:unit test:integration", + "test:unit": "run-s clean build run_mocha_unit", + "test:integration": "run-s clean build run_mocha_integration" }, "dependencies": { "@0xproject/assert": "^0.0.6", diff --git a/packages/subproviders/src/globals.d.ts b/packages/subproviders/src/globals.d.ts index 362587e08..520ca9232 100644 --- a/packages/subproviders/src/globals.d.ts +++ b/packages/subproviders/src/globals.d.ts @@ -1,27 +1,56 @@ /// <reference types='chai-typescript-typings' /> /// <reference types='chai-as-promised-typescript-typings' /> declare module 'dirty-chai'; -declare module 'ledgerco'; -declare module 'ethereumjs-tx'; declare module 'es6-promisify'; // tslint:disable:max-classes-per-file // tslint:disable:class-name // tslint:disable:completed-docs +// Ethereumjs-tx declarations +declare module 'ethereumjs-tx' { + class EthereumTx { + public raw: Buffer[]; + public r: Buffer; + public s: Buffer; + public v: Buffer; + public serialize(): Buffer; + constructor(txParams: any); + } + export = EthereumTx; +} + // Ledgerco declarations +interface ECSignatureString { + v: string; + r: string; + s: string; +} +interface ECSignature { + v: number; + r: string; + s: string; +} declare module 'ledgerco' { interface comm { - close_async: Promise<void>; - create_async: Promise<void>; + close_async(): Promise<void>; } export class comm_node implements comm { - public create_async: Promise<void>; - public close_async: Promise<void>; + public static create_async(timeoutMilliseconds?: number): Promise<comm_node>; + public close_async(): Promise<void>; } export class comm_u2f implements comm { - public create_async: Promise<void>; - public close_async: Promise<void>; + public static create_async(): Promise<comm_u2f>; + public close_async(): Promise<void>; + } + export class eth { + public comm: comm; + constructor(comm: comm); + public getAddress_async(path: string, display?: boolean, chaincode?: boolean): + Promise<{publicKey: string; address: 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>; } } @@ -66,6 +95,3 @@ declare module 'web3-provider-engine' { } export = Web3ProviderEngine; } -// tslint:enable:max-classes-per-file -// tslint:enable:class-name -// tslint:enable:completed-docs diff --git a/packages/subproviders/src/subproviders/ledger.ts b/packages/subproviders/src/subproviders/ledger.ts index ccc94d76f..83c5b6867 100644 --- a/packages/subproviders/src/subproviders/ledger.ts +++ b/packages/subproviders/src/subproviders/ledger.ts @@ -1,6 +1,7 @@ +import {assert} from '@0xproject/assert'; import promisify = require('es6-promisify'); import {isAddress} from 'ethereum-address'; -import * as EthereumTx from 'ethereumjs-tx'; +import EthereumTx = require('ethereumjs-tx'); import ethUtil = require('ethereumjs-util'); import * as ledger from 'ledgerco'; import * as _ from 'lodash'; @@ -14,7 +15,6 @@ import { LedgerSubproviderErrors, PartialTxParams, ResponseWithTxParams, - SignPersonalMessageParams, } from '../types'; import {Subprovider} from './subprovider'; @@ -46,17 +46,6 @@ export class LedgerSubprovider extends Subprovider { const isValid = nonPrefixed.match(HEX_REGEX); return isValid; } - private static validatePersonalMessage(msgParams: PartialTxParams) { - if (_.isUndefined(msgParams.from) || !isAddress(msgParams.from)) { - throw new Error(LedgerSubproviderErrors.FromAddressMissingOrInvalid); - } - if (_.isUndefined(msgParams.data)) { - throw new Error(LedgerSubproviderErrors.DataMissingForSignPersonalMessage); - } - if (!LedgerSubprovider.isValidHex(msgParams.data)) { - throw new Error(LedgerSubproviderErrors.DataNotValidHexForSignPersonalMessage); - } - } private static validateSender(sender: string) { if (_.isUndefined(sender) || !isAddress(sender)) { throw new Error(LedgerSubproviderErrors.SenderInvalidOrNotSupplied); @@ -132,17 +121,13 @@ export class LedgerSubprovider extends Subprovider { return; case 'personal_sign': - // non-standard "extraParams" to be appended to our "msgParams" obj - // good place for metadata - const extraParams = payload.params[2] || {}; - const msgParams = _.assign({}, extraParams, { - from: payload.params[1], - data: payload.params[0], - }); - + const data = payload.params[0]; try { - LedgerSubprovider.validatePersonalMessage(msgParams); - const ecSignatureHex = await this.signPersonalMessageAsync(msgParams); + if (_.isUndefined(data)) { + throw new Error(LedgerSubproviderErrors.DataMissingForSignPersonalMessage); + } + assert.isHexString('data', data); + const ecSignatureHex = await this.signPersonalMessageAsync(data); end(null, ecSignatureHex); } catch (err) { end(err); @@ -208,12 +193,12 @@ export class LedgerSubprovider extends Subprovider { throw err; } } - public async signPersonalMessageAsync(msgParams: SignPersonalMessageParams): Promise<string> { + public async signPersonalMessageAsync(data: string): Promise<string> { this._ledgerClientIfExists = await this.createLedgerClientAsync(); try { const derivationPath = this.getDerivationPath(); const result = await this._ledgerClientIfExists.signPersonalMessage_async( - derivationPath, ethUtil.stripHexPrefix(msgParams.data)); + derivationPath, ethUtil.stripHexPrefix(data)); const v = result.v - 27; let vHex = v.toString(16); if (vHex.length < 2) { @@ -251,7 +236,7 @@ export class LedgerSubprovider extends Subprovider { this._ledgerClientIfExists = undefined; this._connectionLock.signal(); } - private async sendTransactionAsync(txParams: PartialTxParams): Promise<any> { + private async sendTransactionAsync(txParams: PartialTxParams): Promise<Web3.JSONRPCResponsePayload> { await this._nonceLock.wait(); try { // fill in the extras diff --git a/packages/subproviders/src/types.ts b/packages/subproviders/src/types.ts index 4564c5229..38dc1e67e 100644 --- a/packages/subproviders/src/types.ts +++ b/packages/subproviders/src/types.ts @@ -2,8 +2,6 @@ import * as _ from 'lodash'; import * as Web3 from 'web3'; export interface LedgerCommunicationClient { - exchange: (apduHex: string, statusList: number[]) => Promise<any[]>; - setScrambleKey: (key: string) => void; close_async: () => Promise<void>; } @@ -74,10 +72,6 @@ export interface LedgerWalletSubprovider { setPathIndex: (pathIndex: number) => void; } -export interface SignPersonalMessageParams { - data: string; -} - export interface PartialTxParams { nonce: string; gasPrice?: string; @@ -109,7 +103,6 @@ export enum LedgerSubproviderErrors { TooOldLedgerFirmware = 'TOO_OLD_LEDGER_FIRMWARE', FromAddressMissingOrInvalid = 'FROM_ADDRESS_MISSING_OR_INVALID', DataMissingForSignPersonalMessage = 'DATA_MISSING_FOR_SIGN_PERSONAL_MESSAGE', - DataNotValidHexForSignPersonalMessage = 'DATA_NOT_VALID_HEX_FOR_SIGN_PERSONAL_MESSAGE', SenderInvalidOrNotSupplied = 'SENDER_INVALID_OR_NOT_SUPPLIED', MultipleOpenConnectionsDisallowed = 'MULTIPLE_OPEN_CONNECTIONS_DISALLOWED', } diff --git a/packages/subproviders/test/integration/ledger_subprovider_test.ts b/packages/subproviders/test/integration/ledger_subprovider_test.ts index ab1ee3264..75f6d47fe 100644 --- a/packages/subproviders/test/integration/ledger_subprovider_test.ts +++ b/packages/subproviders/test/integration/ledger_subprovider_test.ts @@ -20,6 +20,7 @@ import { import {chaiSetup} from '../chai_setup'; import {reportCallbackErrors} from '../utils/report_callback_errors'; +chaiSetup.configure(); const expect = chai.expect; const TEST_RPC_ACCOUNT_0 = '0x5409ed021d9299bf6814279a6a1411a7e866a631'; @@ -41,7 +42,7 @@ describe('LedgerSubprovider', () => { }); it('signs a personal message', async () => { const data = ethUtils.bufferToHex(ethUtils.toBuffer('hello world')); - const ecSignatureHex = await ledgerSubprovider.signPersonalMessageAsync({data}); + const ecSignatureHex = await ledgerSubprovider.signPersonalMessageAsync(data); expect(ecSignatureHex.length).to.be.equal(132); expect(ecSignatureHex.substr(0, 2)).to.be.equal('0x'); }); diff --git a/packages/subproviders/test/unit/ledger_subprovider_test.ts b/packages/subproviders/test/unit/ledger_subprovider_test.ts index f895e7b74..bc9671948 100644 --- a/packages/subproviders/test/unit/ledger_subprovider_test.ts +++ b/packages/subproviders/test/unit/ledger_subprovider_test.ts @@ -19,6 +19,7 @@ import { import {chaiSetup} from '../chai_setup'; import {reportCallbackErrors} from '../utils/report_callback_errors'; +chaiSetup.configure(); const expect = chai.expect; const FAKE_ADDRESS = '0x9901c66f2d4b95f7074b553da78084d708beca70'; @@ -35,7 +36,7 @@ describe('LedgerSubprovider', () => { }; }, signPersonalMessage_async: async () => { - const ecSignature: ECSignature = { + const ecSignature = { v: 28, r: 'a6cc284bff14b42bdf5e9286730c152be91719d478605ec46b3bebcd0ae49148', s: '0652a1a7b742ceb0213d1e744316e285f41f878d8af0b8e632cbca4c279132d0', @@ -43,7 +44,7 @@ describe('LedgerSubprovider', () => { return ecSignature; }, signTransaction_async: async (derivationPath: string, txHex: string) => { - const ecSignature: ECSignatureString = { + const ecSignature = { v: '77', r: '88a95ef1378487bc82be558e82c8478baf840c545d5b887536bb1da63673a98b', s: '019f4a4b9a107d1e6752bf7f701e275f28c13791d6e76af895b07373462cefaa', @@ -71,8 +72,7 @@ describe('LedgerSubprovider', () => { }); it('signs a personal message', async () => { const data = ethUtils.bufferToHex(ethUtils.toBuffer('hello world')); - const msgParams = {data}; - const ecSignatureHex = await ledgerSubprovider.signPersonalMessageAsync(msgParams); + const ecSignatureHex = await ledgerSubprovider.signPersonalMessageAsync(data); // tslint:disable-next-line:max-line-length expect(ecSignatureHex).to.be.equal('0xa6cc284bff14b42bdf5e9286730c152be91719d478605ec46b3bebcd0ae491480652a1a7b742ceb0213d1e744316e285f41f878d8af0b8e632cbca4c279132d001'); }); @@ -80,16 +80,10 @@ describe('LedgerSubprovider', () => { describe('failure cases', () => { it('cannot open multiple simultaneous connections to the Ledger device', async () => { const data = ethUtils.bufferToHex(ethUtils.toBuffer('hello world')); - const msgParams = {data}; - try { - const result = await Promise.all([ - ledgerSubprovider.getAccountsAsync(), - ledgerSubprovider.signPersonalMessageAsync(msgParams), - ]); - throw new Error('Multiple simultaneous calls succeeded when they should have failed'); - } catch (err) { - expect(err.message).to.be.equal(LedgerSubproviderErrors.MultipleOpenConnectionsDisallowed); - } + return expect(Promise.all([ + ledgerSubprovider.getAccountsAsync(), + ledgerSubprovider.signPersonalMessageAsync(data), + ])).to.be.rejectedWith(LedgerSubproviderErrors.MultipleOpenConnectionsDisallowed); }); }); }); @@ -157,21 +151,6 @@ describe('LedgerSubprovider', () => { }); }); describe('failure cases', () => { - it('should throw if `from` param missing when calling personal_sign', (done: DoneCallback) => { - const messageHex = ethUtils.bufferToHex(ethUtils.toBuffer('hello world')); - const payload = { - jsonrpc: '2.0', - method: 'personal_sign', - params: [messageHex], // Missing from param - id: 1, - }; - const callback = reportCallbackErrors(done)((err: Error, response: Web3.JSONRPCResponsePayload) => { - expect(err).to.not.be.a('null'); - expect(err.message).to.be.equal(LedgerSubproviderErrors.FromAddressMissingOrInvalid); - done(); - }); - provider.sendAsync(payload, callback); - }); it('should throw if `data` param not hex when calling personal_sign', (done: DoneCallback) => { const nonHexMessage = 'hello world'; const payload = { @@ -182,7 +161,7 @@ describe('LedgerSubprovider', () => { }; const callback = reportCallbackErrors(done)((err: Error, response: Web3.JSONRPCResponsePayload) => { expect(err).to.not.be.a('null'); - expect(err.message).to.be.equal(LedgerSubproviderErrors.DataNotValidHexForSignPersonalMessage); + expect(err.message).to.be.equal('Expected data to be of type HexString, encountered: hello world'); done(); }); provider.sendAsync(payload, callback); diff --git a/packages/subproviders/webpack.config.js b/packages/subproviders/webpack.config.js deleted file mode 100644 index a73489704..000000000 --- a/packages/subproviders/webpack.config.js +++ /dev/null @@ -1,56 +0,0 @@ -/** - * This is to generate the umd bundle only - */ -const _ = require('lodash'); -const webpack = require('webpack'); -const path = require('path'); -const production = process.env.NODE_ENV === 'production'; - -let entry = { - 'index': './src/index.ts', -}; -if (production) { - entry = _.assign({}, entry, {'index.min': './src/index.ts'}); -} - -module.exports = { - entry, - output: { - path: path.resolve(__dirname, '_bundles'), - filename: '[name].js', - libraryTarget: 'umd', - library: '0x Subproviders', - umdNamedDefine: true, - }, - resolve: { - extensions: ['.ts', '.js', '.json'], - }, - devtool: 'source-map', - plugins: [ - new webpack.optimize.UglifyJsPlugin({ - minimize: true, - sourceMap: true, - include: /\.min\.js$/, - }), - ], - module: { - rules: [ - { - test: /\.ts$/, - use: [ - { - loader: 'awesome-typescript-loader', - query: { - declaration: false, - }, - }, - ], - exclude: /node_modules/, - }, - { - test: /\.json$/, - loader: 'json-loader', - }, - ], - }, -}; diff --git a/packages/website/package.json b/packages/website/package.json index fc7d65d05..ac6e61a88 100644 --- a/packages/website/package.json +++ b/packages/website/package.json @@ -18,7 +18,7 @@ "author": "Fabio Berger", "license": "Apache-2.0", "dependencies": { - "@0xproject/subproviders": "0.0.0", + "@0xproject/subproviders": "0.0.1", "0x.js": "0xproject/0x.js/packages/0x.js#0x.js@0.27.1", "accounting": "^0.4.1", "basscss": "^8.0.3", diff --git a/packages/website/ts/components/ui/lifecycle_raised_button.tsx b/packages/website/ts/components/ui/lifecycle_raised_button.tsx index 338a3bf76..cba94ca8c 100644 --- a/packages/website/ts/components/ui/lifecycle_raised_button.tsx +++ b/packages/website/ts/components/ui/lifecycle_raised_button.tsx @@ -20,7 +20,7 @@ interface LifeCycleRaisedButtonProps { labelReady: React.ReactNode|string; labelLoading: React.ReactNode|string; labelComplete: React.ReactNode|string; - onClickAsyncFn: () => boolean; + onClickAsyncFn: () => Promise<boolean>; backgroundColor?: string; labelColor?: string; } diff --git a/packages/website/ts/globals.d.ts b/packages/website/ts/globals.d.ts index 46897b429..38a4b971e 100644 --- a/packages/website/ts/globals.d.ts +++ b/packages/website/ts/globals.d.ts @@ -163,5 +163,3 @@ declare interface Artifact { }; }; } - -// tslint:enable:max-classes-per-file |