aboutsummaryrefslogtreecommitdiffstats
path: root/packages/website/ts
diff options
context:
space:
mode:
Diffstat (limited to 'packages/website/ts')
-rw-r--r--packages/website/ts/blockchain.ts44
-rw-r--r--packages/website/ts/components/ui/lifecycle_raised_button.tsx2
-rw-r--r--packages/website/ts/globals.d.ts32
-rw-r--r--packages/website/ts/subproviders/injected_web3_subprovider.ts45
-rw-r--r--packages/website/ts/subproviders/ledger_wallet_subprovider_factory.ts172
-rw-r--r--packages/website/ts/subproviders/redundant_rpc_subprovider.ts43
-rw-r--r--packages/website/ts/types.ts6
7 files changed, 43 insertions, 301 deletions
diff --git a/packages/website/ts/blockchain.ts b/packages/website/ts/blockchain.ts
index aea4f863c..809da7d4f 100644
--- a/packages/website/ts/blockchain.ts
+++ b/packages/website/ts/blockchain.ts
@@ -16,6 +16,13 @@ import {
ZeroEx,
ZeroExError,
} from '0x.js';
+import {
+ InjectedWeb3Subprovider,
+ ledgerEthereumBrowserClientFactoryAsync,
+ LedgerSubprovider,
+ LedgerWalletSubprovider,
+ RedundantRPCSubprovider,
+} from '@0xproject/subproviders';
import BigNumber from 'bignumber.js';
import compareVersions = require('compare-versions');
import promisify = require('es6-promisify');
@@ -25,20 +32,16 @@ import * as _ from 'lodash';
import * as React from 'react';
import contract = require('truffle-contract');
import {TokenSendCompleted} from 'ts/components/flash_messages/token_send_completed';
-import { TransactionSubmitted } from 'ts/components/flash_messages/transaction_submitted';
+import {TransactionSubmitted} from 'ts/components/flash_messages/transaction_submitted';
import {trackedTokenStorage} from 'ts/local_storage/tracked_token_storage';
import {tradeHistoryStorage} from 'ts/local_storage/trade_history_storage';
import {Dispatcher} from 'ts/redux/dispatcher';
-import {InjectedWeb3SubProvider} from 'ts/subproviders/injected_web3_subprovider';
-import {ledgerWalletSubproviderFactory} from 'ts/subproviders/ledger_wallet_subprovider_factory';
-import {RedundantRPCSubprovider} from 'ts/subproviders/redundant_rpc_subprovider';
import {
BlockchainCallErrs,
BlockchainErrs,
ContractInstance,
ContractResponse,
EtherscanLinkSuffixes,
- LedgerWalletSubprovider,
ProviderType,
Side,
SignatureData,
@@ -71,7 +74,7 @@ export class Blockchain {
private tokenRegistry: ContractInstance;
private userAddress: string;
private cachedProvider: Web3.Provider;
- private ledgerSubProvider: LedgerWalletSubprovider;
+ private ledgerSubprovider: LedgerWalletSubprovider;
private zrxPollIntervalId: number;
private static async onPageLoadAsync() {
if (document.readyState === 'complete') {
@@ -105,7 +108,7 @@ export class Blockchain {
// We catch all requests involving a users account and send it to the injectedWeb3
// instance. All other requests go to the public hosted node.
provider = new ProviderEngine();
- provider.addProvider(new InjectedWeb3SubProvider(injectedWeb3));
+ provider.addProvider(new InjectedWeb3Subprovider(injectedWeb3));
provider.addProvider(new FilterSubprovider());
provider.addProvider(new RedundantRPCSubprovider(
publicNodeUrlsIfExistsForNetworkId,
@@ -168,23 +171,23 @@ export class Blockchain {
return !_.isUndefined(tokenIfExists);
}
public getLedgerDerivationPathIfExists(): string {
- if (_.isUndefined(this.ledgerSubProvider)) {
+ if (_.isUndefined(this.ledgerSubprovider)) {
return undefined;
}
- const path = this.ledgerSubProvider.getPath();
+ const path = this.ledgerSubprovider.getPath();
return path;
}
public updateLedgerDerivationPathIfExists(path: string) {
- if (_.isUndefined(this.ledgerSubProvider)) {
+ if (_.isUndefined(this.ledgerSubprovider)) {
return; // noop
}
- this.ledgerSubProvider.setPath(path);
+ this.ledgerSubprovider.setPath(path);
}
public updateLedgerDerivationIndex(pathIndex: number) {
- if (_.isUndefined(this.ledgerSubProvider)) {
+ if (_.isUndefined(this.ledgerSubprovider)) {
return; // noop
}
- this.ledgerSubProvider.setPathIndex(pathIndex);
+ this.ledgerSubprovider.setPathIndex(pathIndex);
}
public async providerTypeUpdatedFireAndForgetAsync(providerType: ProviderType) {
utils.assert(!_.isUndefined(this.zeroEx), 'ZeroEx must be instantiated.');
@@ -204,8 +207,12 @@ export class Blockchain {
this.dispatcher.updateUserAddress(''); // Clear old userAddress
provider = new ProviderEngine();
- this.ledgerSubProvider = ledgerWalletSubproviderFactory(this.getBlockchainNetworkId.bind(this));
- provider.addProvider(this.ledgerSubProvider);
+ const ledgerWalletConfigs = {
+ networkId: this.networkId,
+ ledgerEthereumClientFactoryAsync: ledgerEthereumBrowserClientFactoryAsync,
+ };
+ this.ledgerSubprovider = new LedgerSubprovider(ledgerWalletConfigs);
+ provider.addProvider(this.ledgerSubprovider);
provider.addProvider(new FilterSubprovider());
const networkId = configs.isMainnetEnabled ?
constants.MAINNET_NETWORK_ID :
@@ -231,7 +238,7 @@ export class Blockchain {
this.web3Wrapper = new Web3Wrapper(this.dispatcher, provider, this.networkId, shouldPollUserAddress);
this.zeroEx.setProvider(provider, this.networkId);
await this.postInstantiationOrUpdatingProviderZeroExAsync();
- delete this.ledgerSubProvider;
+ delete this.ledgerSubprovider;
delete this.cachedProvider;
break;
}
@@ -657,11 +664,6 @@ export class Blockchain {
constants.PUBLIC_PROVIDER_NAME;
this.dispatcher.updateInjectedProviderName(providerName);
}
- // This is only ever called by the LedgerWallet subprovider in order to retrieve
- // the current networkId without this value going stale.
- private getBlockchainNetworkId() {
- return this.networkId;
- }
private async fetchTokenInformationAsync() {
utils.assert(!_.isUndefined(this.networkId),
'Cannot call fetchTokenInformationAsync if disconnected from Ethereum node');
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 c5b94dc45..38a4b971e 100644
--- a/packages/website/ts/globals.d.ts
+++ b/packages/website/ts/globals.d.ts
@@ -4,7 +4,6 @@ declare module 'es6-promisify';
declare module 'truffle-contract';
declare module 'ethereumjs-util';
declare module 'keccak';
-declare module 'web3-provider-engine';
declare module 'whatwg-fetch';
declare module 'react-html5video';
declare module 'web3-provider-engine/subproviders/filters';
@@ -22,6 +21,8 @@ declare module '*.json' {
/* tslint:enable */
}
+// tslint:disable:max-classes-per-file
+
// find-version declarations
declare function findVersions(version: string): string[];
declare module 'find-versions' {
@@ -132,21 +133,26 @@ declare class Subprovider {}
declare module 'web3-provider-engine/subproviders/subprovider' {
export = Subprovider;
}
-
-// tslint:disable-next-line:max-classes-per-file
-declare class RpcSubprovider {
- constructor(options: {rpcUrl: string});
- public handleRequest(payload: any, next: any, end: (err?: Error, data?: any) => void): void;
-}
declare module 'web3-provider-engine/subproviders/rpc' {
+ import * as Web3 from 'web3';
+ class RpcSubprovider {
+ constructor(options: {rpcUrl: string});
+ public handleRequest(
+ payload: Web3.JSONRPCRequestPayload, next: () => void, end: (err: Error|null, data?: any) => void,
+ ): void;
+ }
export = RpcSubprovider;
}
-// tslint:disable-next-line:max-classes-per-file
-declare class HookedWalletSubprovider {
- constructor(wallet: any);
-}
-declare module 'web3-provider-engine/subproviders/hooked-wallet' {
- export = HookedWalletSubprovider;
+declare module 'web3-provider-engine' {
+ class Web3ProviderEngine {
+ public on(event: string, handler: () => void): void;
+ public send(payload: any): void;
+ public sendAsync(payload: any, callback: (error: any, response: any) => void): void;
+ public addProvider(provider: any): void;
+ public start(): void;
+ public stop(): void;
+ }
+ export = Web3ProviderEngine;
}
declare interface Artifact {
diff --git a/packages/website/ts/subproviders/injected_web3_subprovider.ts b/packages/website/ts/subproviders/injected_web3_subprovider.ts
deleted file mode 100644
index 910fe3cdf..000000000
--- a/packages/website/ts/subproviders/injected_web3_subprovider.ts
+++ /dev/null
@@ -1,45 +0,0 @@
-import * as _ from 'lodash';
-import {constants} from 'ts/utils/constants';
-import Web3 = require('web3');
-
-/*
- * This class implements the web3-provider-engine subprovider interface and forwards
- * requests involving user accounts (getAccounts, sendTransaction, etc...) to the injected
- * web3 instance in their browser.
- * Source: https://github.com/MetaMask/provider-engine/blob/master/subproviders/subprovider.js
- */
-export class InjectedWeb3SubProvider {
- private injectedWeb3: Web3;
- constructor(injectedWeb3: Web3) {
- this.injectedWeb3 = injectedWeb3;
- }
- public handleRequest(payload: any, next: () => void, end: (err: Error, result: any) => void) {
- switch (payload.method) {
- case 'web3_clientVersion':
- this.injectedWeb3.version.getNode(end);
- return;
- case 'eth_accounts':
- this.injectedWeb3.eth.getAccounts(end);
- return;
-
- case 'eth_sendTransaction':
- const [txParams] = payload.params;
- this.injectedWeb3.eth.sendTransaction(txParams, end);
- return;
-
- case 'eth_sign':
- const [address, message] = payload.params;
- this.injectedWeb3.eth.sign(address, message, end);
- return;
-
- default:
- next();
- return;
- }
- }
- // Required to implement this method despite not needing it for this subprovider
- // tslint:disable-next-line:prefer-function-over-method
- public setEngine(engine: any) {
- // noop
- }
-}
diff --git a/packages/website/ts/subproviders/ledger_wallet_subprovider_factory.ts b/packages/website/ts/subproviders/ledger_wallet_subprovider_factory.ts
deleted file mode 100644
index bfabc90ae..000000000
--- a/packages/website/ts/subproviders/ledger_wallet_subprovider_factory.ts
+++ /dev/null
@@ -1,172 +0,0 @@
-import * as EthereumTx from 'ethereumjs-tx';
-import ethUtil = require('ethereumjs-util');
-import * as ledger from 'ledgerco';
-import * as _ from 'lodash';
-import {LedgerEthConnection, SignPersonalMessageParams, TxParams} from 'ts/types';
-import {constants} from 'ts/utils/constants';
-import Web3 = require('web3');
-import HookedWalletSubprovider = require('web3-provider-engine/subproviders/hooked-wallet');
-
-const NUM_ADDRESSES_TO_FETCH = 10;
-const ASK_FOR_ON_DEVICE_CONFIRMATION = false;
-const SHOULD_GET_CHAIN_CODE = false;
-
-export class LedgerWallet {
- public isU2FSupported: boolean;
- public getAccounts: (callback: (err: Error, accounts: string[]) => void) => void;
- public signMessage: (msgParams: SignPersonalMessageParams,
- callback: (err: Error, result?: string) => void) => void;
- public signTransaction: (txParams: TxParams,
- callback: (err: Error, result?: string) => void) => void;
- private getNetworkId: () => number;
- private path: string;
- private pathIndex: number;
- private ledgerEthConnection: LedgerEthConnection;
- private accounts: string[];
- constructor(getNetworkIdFn: () => number) {
- this.path = constants.DEFAULT_DERIVATION_PATH;
- this.pathIndex = 0;
- this.isU2FSupported = false;
- this.getNetworkId = getNetworkIdFn;
- this.getAccounts = this.getAccountsAsync.bind(this);
- this.signMessage = this.signPersonalMessageAsync.bind(this);
- this.signTransaction = this.signTransactionAsync.bind(this);
- }
- public getPath(): string {
- return this.path;
- }
- public setPath(derivationPath: string) {
- this.path = derivationPath;
- // HACK: Must re-assign getAccounts, signMessage and signTransaction since they were
- // previously bound to old values of this.path
- this.getAccounts = this.getAccountsAsync.bind(this);
- this.signMessage = this.signPersonalMessageAsync.bind(this);
- this.signTransaction = this.signTransactionAsync.bind(this);
- }
- public setPathIndex(pathIndex: number) {
- this.pathIndex = pathIndex;
- // HACK: Must re-assign signMessage & signTransaction since they it was previously bound to
- // old values of this.path
- this.signMessage = this.signPersonalMessageAsync.bind(this);
- this.signTransaction = this.signTransactionAsync.bind(this);
- }
- public async getAccountsAsync(callback: (err: Error, accounts: string[]) => void) {
- if (!_.isUndefined(this.ledgerEthConnection)) {
- callback(null, []);
- return;
- }
- this.ledgerEthConnection = await this.createLedgerConnectionAsync();
-
- const accounts = [];
- for (let i = 0; i < NUM_ADDRESSES_TO_FETCH; i++) {
- try {
- const derivationPath = `${this.path}/${i}`;
- const result = await this.ledgerEthConnection.getAddress_async(
- derivationPath, ASK_FOR_ON_DEVICE_CONFIRMATION, SHOULD_GET_CHAIN_CODE,
- );
- accounts.push(result.address.toLowerCase());
- } catch (err) {
- await this.closeLedgerConnectionAsync();
- callback(err, null);
- return;
- }
- }
-
- await this.closeLedgerConnectionAsync();
- callback(null, accounts);
- }
- public async signTransactionAsync(txParams: TxParams, callback: (err: Error, result?: string) => void) {
- const tx = new EthereumTx(txParams);
-
- const networkId = this.getNetworkId();
- const chainId = networkId; // Same thing
-
- // Set the EIP155 bits
- tx.raw[6] = Buffer.from([chainId]); // v
- tx.raw[7] = Buffer.from([]); // r
- tx.raw[8] = Buffer.from([]); // s
-
- const txHex = tx.serialize().toString('hex');
-
- this.ledgerEthConnection = await this.createLedgerConnectionAsync();
-
- try {
- const derivationPath = this.getDerivationPath();
- const result = await this.ledgerEthConnection.signTransaction_async(derivationPath, txHex);
-
- // Store signature in transaction
- tx.v = new Buffer(result.v, 'hex');
- tx.r = new Buffer(result.r, 'hex');
- tx.s = new Buffer(result.s, 'hex');
-
- // EIP155: v should be chain_id * 2 + {35, 36}
- const signedChainId = Math.floor((tx.v[0] - 35) / 2);
- if (signedChainId !== chainId) {
- const err = new Error('TOO_OLD_LEDGER_FIRMWARE');
- callback(err, null);
- return;
- }
-
- const signedTxHex = `0x${tx.serialize().toString('hex')}`;
- await this.closeLedgerConnectionAsync();
- callback(null, signedTxHex);
- } catch (err) {
- await this.closeLedgerConnectionAsync();
- callback(err, null);
- }
- }
- public async signPersonalMessageAsync(msgParams: SignPersonalMessageParams,
- callback: (err: Error, result?: string) => void) {
- if (!_.isUndefined(this.ledgerEthConnection)) {
- callback(new Error('Another request is in progress.'));
- return;
- }
- this.ledgerEthConnection = await this.createLedgerConnectionAsync();
-
- try {
- const derivationPath = this.getDerivationPath();
- const result = await this.ledgerEthConnection.signPersonalMessage_async(
- derivationPath, ethUtil.stripHexPrefix(msgParams.data),
- );
- const v = _.parseInt(result.v) - 27;
- let vHex = v.toString(16);
- if (vHex.length < 2) {
- vHex = `0${v}`;
- }
- const signature = `0x${result.r}${result.s}${vHex}`;
- await this.closeLedgerConnectionAsync();
- callback(null, signature);
- } catch (err) {
- await this.closeLedgerConnectionAsync();
- callback(err, null);
- }
- }
- private async createLedgerConnectionAsync() {
- if (!_.isUndefined(this.ledgerEthConnection)) {
- throw new Error('Multiple open connections to the Ledger disallowed.');
- }
- const ledgerConnection = await ledger.comm_u2f.create_async();
- const ledgerEthConnection = new ledger.eth(ledgerConnection);
- return ledgerEthConnection;
- }
- private async closeLedgerConnectionAsync() {
- if (_.isUndefined(this.ledgerEthConnection)) {
- return;
- }
- await this.ledgerEthConnection.comm.close_async();
- this.ledgerEthConnection = undefined;
- }
- private getDerivationPath() {
- const derivationPath = `${this.path}/${this.pathIndex}`;
- return derivationPath;
- }
-}
-
-export const ledgerWalletSubproviderFactory = (getNetworkIdFn: () => number): LedgerWallet => {
- const ledgerWallet = new LedgerWallet(getNetworkIdFn);
- const ledgerWalletSubprovider = new HookedWalletSubprovider(ledgerWallet) as LedgerWallet;
- ledgerWalletSubprovider.getPath = ledgerWallet.getPath.bind(ledgerWallet);
- ledgerWalletSubprovider.setPath = ledgerWallet.setPath.bind(ledgerWallet);
- ledgerWalletSubprovider.setPathIndex = ledgerWallet.setPathIndex.bind(ledgerWallet);
- return ledgerWalletSubprovider;
-};
diff --git a/packages/website/ts/subproviders/redundant_rpc_subprovider.ts b/packages/website/ts/subproviders/redundant_rpc_subprovider.ts
deleted file mode 100644
index 8dffd4437..000000000
--- a/packages/website/ts/subproviders/redundant_rpc_subprovider.ts
+++ /dev/null
@@ -1,43 +0,0 @@
-import promisify = require('es6-promisify');
-import * as _ from 'lodash';
-import {JSONRPCPayload} from 'ts/types';
-import RpcSubprovider = require('web3-provider-engine/subproviders/rpc');
-import Subprovider = require('web3-provider-engine/subproviders/subprovider');
-
-export class RedundantRPCSubprovider extends Subprovider {
- private rpcs: RpcSubprovider[];
- private static async firstSuccessAsync(
- rpcs: RpcSubprovider[], payload: JSONRPCPayload, next: () => void,
- ): Promise<any> {
- let lastErr;
- for (const rpc of rpcs) {
- try {
- const data = await promisify(rpc.handleRequest.bind(rpc))(payload, next);
- return data;
- } catch (err) {
- lastErr = err;
- continue;
- }
- }
- throw Error(lastErr);
- }
- constructor(endpoints: string[]) {
- super();
- this.rpcs = _.map(endpoints, endpoint => {
- return new RpcSubprovider({
- rpcUrl: endpoint,
- });
- });
- }
- public async handleRequest(payload: JSONRPCPayload, next: () => void,
- end: (err?: Error, data?: any) => void): Promise<void> {
- const rpcsCopy = this.rpcs.slice();
- try {
- const data = await RedundantRPCSubprovider.firstSuccessAsync(rpcsCopy, payload, next);
- end(null, data);
- } catch (err) {
- end(err);
- }
-
- }
-}
diff --git a/packages/website/ts/types.ts b/packages/website/ts/types.ts
index d2c690ce1..d225e7784 100644
--- a/packages/website/ts/types.ts
+++ b/packages/website/ts/types.ts
@@ -521,12 +521,6 @@ export interface SignPersonalMessageParams {
data: string;
}
-export interface LedgerWalletSubprovider {
- getPath: () => string;
- setPath: (path: string) => void;
- setPathIndex: (pathIndex: number) => void;
-}
-
export interface TxParams {
nonce: string;
gasPrice?: number;