Merge branch 'v2-prototype' of https://github.com/0xProject/0x-monorepo into bug/website/txhash-error
This commit is contained in:
@@ -105,6 +105,7 @@
|
|||||||
"@0xproject/contract-wrappers": "^0.1.0",
|
"@0xproject/contract-wrappers": "^0.1.0",
|
||||||
"@0xproject/order-utils": "^1.0.0",
|
"@0xproject/order-utils": "^1.0.0",
|
||||||
"@0xproject/sol-compiler": "^0.5.3",
|
"@0xproject/sol-compiler": "^0.5.3",
|
||||||
|
"@0xproject/subproviders": "^0.10.5",
|
||||||
"@0xproject/types": "^1.0.0",
|
"@0xproject/types": "^1.0.0",
|
||||||
"@0xproject/typescript-typings": "^0.4.2",
|
"@0xproject/typescript-typings": "^0.4.2",
|
||||||
"@0xproject/utils": "^0.7.2",
|
"@0xproject/utils": "^0.7.2",
|
||||||
|
File diff suppressed because one or more lines are too long
@@ -1,6 +1,7 @@
|
|||||||
export { ZeroEx } from './0x';
|
export { ZeroEx } from './0x';
|
||||||
|
|
||||||
export { MessagePrefixType, MessagePrefixOpts } from '@0xproject/order-utils';
|
export { MessagePrefixType, MessagePrefixOpts } from '@0xproject/order-utils';
|
||||||
|
export { Web3ProviderEngine, RPCSubprovider } from '@0xproject/subproviders';
|
||||||
|
|
||||||
export {
|
export {
|
||||||
ExchangeContractErrs,
|
ExchangeContractErrs,
|
||||||
|
@@ -2,7 +2,6 @@ import * as chai from 'chai';
|
|||||||
import * as dirtyChai from 'dirty-chai';
|
import * as dirtyChai from 'dirty-chai';
|
||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
import 'mocha';
|
import 'mocha';
|
||||||
import * as sleep from 'sleep';
|
|
||||||
import * as tmp from 'tmp';
|
import * as tmp from 'tmp';
|
||||||
|
|
||||||
import { utils } from '../src/utils';
|
import { utils } from '../src/utils';
|
||||||
@@ -13,8 +12,6 @@ chai.use(dirtyChai);
|
|||||||
|
|
||||||
const expect = chai.expect;
|
const expect = chai.expect;
|
||||||
|
|
||||||
const SLEEP_MS = 10; // time to wait before re-timestamping a file
|
|
||||||
|
|
||||||
describe('makeOutputFileName()', () => {
|
describe('makeOutputFileName()', () => {
|
||||||
it('should handle Metacoin usage', () => {
|
it('should handle Metacoin usage', () => {
|
||||||
expect(utils.makeOutputFileName('Metacoin')).to.equal('metacoin');
|
expect(utils.makeOutputFileName('Metacoin')).to.equal('metacoin');
|
||||||
@@ -65,19 +62,22 @@ describe('isOutputFileUpToDate()', () => {
|
|||||||
describe('with an existing output file', () => {
|
describe('with an existing output file', () => {
|
||||||
let outputFile: string;
|
let outputFile: string;
|
||||||
before(() => {
|
before(() => {
|
||||||
sleep.msleep(SLEEP_MS); // to ensure different timestamp
|
|
||||||
outputFile = tmp.fileSync(
|
outputFile = tmp.fileSync(
|
||||||
{ discardDescriptor: true }, // close file (set timestamp)
|
{ discardDescriptor: true }, // close file (set timestamp)
|
||||||
).name;
|
).name;
|
||||||
|
const abiFileModTimeMs = fs.statSync(abiFile).mtimeMs;
|
||||||
|
const outfileModTimeMs = abiFileModTimeMs + 1;
|
||||||
|
fs.utimesSync(outputFile, outfileModTimeMs, outfileModTimeMs);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return true when output file and is newer than abi file', async () => {
|
it('should return true when output file is newer than abi file', async () => {
|
||||||
expect(utils.isOutputFileUpToDate(abiFile, outputFile)).to.be.true();
|
expect(utils.isOutputFileUpToDate(abiFile, outputFile)).to.be.true();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return false when output file exists but is older than abi file', () => {
|
it('should return false when output file exists but is older than abi file', () => {
|
||||||
sleep.msleep(SLEEP_MS); // to ensure different timestamp
|
const outFileModTimeMs = fs.statSync(outputFile).mtimeMs;
|
||||||
fs.closeSync(fs.openSync(abiFile, 'w')); // touch abi file
|
const abiFileModTimeMs = outFileModTimeMs + 1;
|
||||||
|
fs.utimesSync(abiFile, abiFileModTimeMs, abiFileModTimeMs);
|
||||||
|
|
||||||
expect(utils.isOutputFileUpToDate(abiFile, outputFile)).to.be.false();
|
expect(utils.isOutputFileUpToDate(abiFile, outputFile)).to.be.false();
|
||||||
});
|
});
|
||||||
|
@@ -56,7 +56,6 @@
|
|||||||
"@0xproject/types": "^0.8.2",
|
"@0xproject/types": "^0.8.2",
|
||||||
"@0xproject/typescript-typings": "^0.4.2",
|
"@0xproject/typescript-typings": "^0.4.2",
|
||||||
"@0xproject/utils": "^0.7.2",
|
"@0xproject/utils": "^0.7.2",
|
||||||
"isomorphic-fetch": "^2.2.1",
|
|
||||||
"lodash": "^4.17.4",
|
"lodash": "^4.17.4",
|
||||||
"query-string": "^5.0.1",
|
"query-string": "^5.0.1",
|
||||||
"sinon": "^4.0.0",
|
"sinon": "^4.0.0",
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
import { assert } from '@0xproject/assert';
|
import { assert } from '@0xproject/assert';
|
||||||
import { schemas } from '@0xproject/json-schemas';
|
import { schemas } from '@0xproject/json-schemas';
|
||||||
import { SignedOrder } from '@0xproject/types';
|
import { SignedOrder } from '@0xproject/types';
|
||||||
import 'isomorphic-fetch';
|
import { fetchAsync } from '@0xproject/utils';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
import * as queryString from 'query-string';
|
import * as queryString from 'query-string';
|
||||||
|
|
||||||
@@ -167,7 +167,7 @@ export class HttpClient implements Client {
|
|||||||
const headers = new Headers({
|
const headers = new Headers({
|
||||||
'content-type': 'application/json',
|
'content-type': 'application/json',
|
||||||
});
|
});
|
||||||
const response = await fetch(url, {
|
const response = await fetchAsync(url, {
|
||||||
method: requestType,
|
method: requestType,
|
||||||
body: JSON.stringify(payload),
|
body: JSON.stringify(payload),
|
||||||
headers,
|
headers,
|
||||||
|
@@ -70,8 +70,7 @@
|
|||||||
"sinon": "^4.0.0",
|
"sinon": "^4.0.0",
|
||||||
"source-map-support": "^0.5.0",
|
"source-map-support": "^0.5.0",
|
||||||
"tslint": "5.8.0",
|
"tslint": "5.8.0",
|
||||||
"typescript": "2.7.1",
|
"typescript": "2.7.1"
|
||||||
"web3-provider-engine": "14.0.6"
|
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@0xproject/assert": "^0.3.0",
|
"@0xproject/assert": "^0.3.0",
|
||||||
|
@@ -1,11 +1,10 @@
|
|||||||
import { BlockchainLifecycle, callbackErrorReporter } from '@0xproject/dev-utils';
|
import { BlockchainLifecycle, callbackErrorReporter } from '@0xproject/dev-utils';
|
||||||
import { EmptyWalletSubprovider } from '@0xproject/subproviders';
|
import { EmptyWalletSubprovider, Web3ProviderEngine } from '@0xproject/subproviders';
|
||||||
import { DoneCallback } from '@0xproject/types';
|
import { DoneCallback } from '@0xproject/types';
|
||||||
import { BigNumber } from '@0xproject/utils';
|
import { BigNumber } from '@0xproject/utils';
|
||||||
import * as chai from 'chai';
|
import * as chai from 'chai';
|
||||||
import { Provider } from 'ethereum-types';
|
import { Provider } from 'ethereum-types';
|
||||||
import 'mocha';
|
import 'mocha';
|
||||||
import Web3ProviderEngine = require('web3-provider-engine');
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
BlockParamLiteral,
|
BlockParamLiteral,
|
||||||
|
@@ -1,11 +1,10 @@
|
|||||||
import { BlockchainLifecycle, callbackErrorReporter } from '@0xproject/dev-utils';
|
import { BlockchainLifecycle, callbackErrorReporter } from '@0xproject/dev-utils';
|
||||||
import { EmptyWalletSubprovider } from '@0xproject/subproviders';
|
import { EmptyWalletSubprovider, Web3ProviderEngine } from '@0xproject/subproviders';
|
||||||
import { DoneCallback } from '@0xproject/types';
|
import { DoneCallback } from '@0xproject/types';
|
||||||
import { BigNumber } from '@0xproject/utils';
|
import { BigNumber } from '@0xproject/utils';
|
||||||
import * as chai from 'chai';
|
import * as chai from 'chai';
|
||||||
import { Provider } from 'ethereum-types';
|
import { Provider } from 'ethereum-types';
|
||||||
import 'mocha';
|
import 'mocha';
|
||||||
import Web3ProviderEngine = require('web3-provider-engine');
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
BlockParamLiteral,
|
BlockParamLiteral,
|
||||||
|
@@ -51,8 +51,7 @@
|
|||||||
"ethereum-types": "^0.0.2",
|
"ethereum-types": "^0.0.2",
|
||||||
"@0xproject/typescript-typings": "^0.4.2",
|
"@0xproject/typescript-typings": "^0.4.2",
|
||||||
"@0xproject/web3-wrapper": "^0.7.2",
|
"@0xproject/web3-wrapper": "^0.7.2",
|
||||||
"lodash": "^4.17.4",
|
"lodash": "^4.17.4"
|
||||||
"web3-provider-engine": "14.0.6"
|
|
||||||
},
|
},
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"access": "public"
|
"access": "public"
|
||||||
|
@@ -1,7 +1,10 @@
|
|||||||
import ProviderEngine = require('web3-provider-engine');
|
import {
|
||||||
import RpcSubprovider = require('web3-provider-engine/subproviders/rpc');
|
EmptyWalletSubprovider,
|
||||||
|
FakeGasEstimateSubprovider,
|
||||||
import { EmptyWalletSubprovider, FakeGasEstimateSubprovider, GanacheSubprovider } from '@0xproject/subproviders';
|
GanacheSubprovider,
|
||||||
|
RPCSubprovider,
|
||||||
|
Web3ProviderEngine,
|
||||||
|
} from '@0xproject/subproviders';
|
||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
|
|
||||||
@@ -16,8 +19,8 @@ export interface Web3Config {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const web3Factory = {
|
export const web3Factory = {
|
||||||
getRpcProvider(config: Web3Config = {}): ProviderEngine {
|
getRpcProvider(config: Web3Config = {}): Web3ProviderEngine {
|
||||||
const provider = new ProviderEngine();
|
const provider = new Web3ProviderEngine();
|
||||||
const hasAddresses = _.isUndefined(config.hasAddresses) || config.hasAddresses;
|
const hasAddresses = _.isUndefined(config.hasAddresses) || config.hasAddresses;
|
||||||
config.shouldUseFakeGasEstimate =
|
config.shouldUseFakeGasEstimate =
|
||||||
_.isUndefined(config.shouldUseFakeGasEstimate) || config.shouldUseFakeGasEstimate;
|
_.isUndefined(config.shouldUseFakeGasEstimate) || config.shouldUseFakeGasEstimate;
|
||||||
@@ -49,11 +52,7 @@ export const web3Factory = {
|
|||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
provider.addProvider(
|
provider.addProvider(new RPCSubprovider(config.rpcUrl || constants.RPC_URL));
|
||||||
new RpcSubprovider({
|
|
||||||
rpcUrl: config.rpcUrl || constants.RPC_URL,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
provider.start();
|
provider.start();
|
||||||
return provider;
|
return provider;
|
||||||
|
@@ -44,8 +44,7 @@
|
|||||||
"ethereum-types": "^0.0.2",
|
"ethereum-types": "^0.0.2",
|
||||||
"ethers": "3.0.22",
|
"ethers": "3.0.22",
|
||||||
"lodash": "^4.17.4",
|
"lodash": "^4.17.4",
|
||||||
"run-s": "^0.0.0",
|
"run-s": "^0.0.0"
|
||||||
"web3-provider-engine": "14.0.6"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@0xproject/dev-utils": "^0.4.5",
|
"@0xproject/dev-utils": "^0.4.5",
|
||||||
|
@@ -1,10 +1,8 @@
|
|||||||
import { env, EnvVars } from '@0xproject/dev-utils';
|
import { env, EnvVars } from '@0xproject/dev-utils';
|
||||||
import { GanacheSubprovider, prependSubprovider } from '@0xproject/subproviders';
|
import { GanacheSubprovider, prependSubprovider, RPCSubprovider, Web3ProviderEngine } from '@0xproject/subproviders';
|
||||||
import { errorUtils, logUtils } from '@0xproject/utils';
|
import { errorUtils, logUtils } from '@0xproject/utils';
|
||||||
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
import ProviderEngine = require('web3-provider-engine');
|
|
||||||
import RpcSubprovider = require('web3-provider-engine/subproviders/rpc');
|
|
||||||
|
|
||||||
import { config } from './config';
|
import { config } from './config';
|
||||||
import { coverage } from './coverage';
|
import { coverage } from './coverage';
|
||||||
@@ -30,7 +28,7 @@ switch (process.env.TEST_PROVIDER) {
|
|||||||
throw errorUtils.spawnSwitchErr('TEST_PROVIDER', process.env.TEST_PROVIDER);
|
throw errorUtils.spawnSwitchErr('TEST_PROVIDER', process.env.TEST_PROVIDER);
|
||||||
}
|
}
|
||||||
|
|
||||||
export const provider = new ProviderEngine();
|
export const provider = new Web3ProviderEngine();
|
||||||
if (testProvider === ProviderType.Ganache) {
|
if (testProvider === ProviderType.Ganache) {
|
||||||
provider.addProvider(
|
provider.addProvider(
|
||||||
new GanacheSubprovider({
|
new GanacheSubprovider({
|
||||||
@@ -45,7 +43,7 @@ if (testProvider === ProviderType.Ganache) {
|
|||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
provider.addProvider(new RpcSubprovider({ rpcUrl: 'http://localhost:8501' }));
|
provider.addProvider(new RPCSubprovider('http://localhost:8501'));
|
||||||
}
|
}
|
||||||
provider.start();
|
provider.start();
|
||||||
|
|
||||||
|
@@ -60,8 +60,7 @@
|
|||||||
"@ledgerhq/hw-app-eth": "^4.3.0",
|
"@ledgerhq/hw-app-eth": "^4.3.0",
|
||||||
"ethereum-types": "^0.0.2",
|
"ethereum-types": "^0.0.2",
|
||||||
"ethers": "3.0.22",
|
"ethers": "3.0.22",
|
||||||
"lodash": "^4.17.4",
|
"lodash": "^4.17.4"
|
||||||
"web3-provider-engine": "14.0.6"
|
|
||||||
},
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"@ledgerhq/hw-transport-node-hid": "^4.3.0"
|
"@ledgerhq/hw-transport-node-hid": "^4.3.0"
|
||||||
|
@@ -1,10 +1,8 @@
|
|||||||
import { LedgerEthereumClient, LedgerSubprovider } from '@0xproject/subproviders';
|
import { LedgerEthereumClient, LedgerSubprovider, RPCSubprovider, Web3ProviderEngine } from '@0xproject/subproviders';
|
||||||
import Eth from '@ledgerhq/hw-app-eth';
|
import Eth from '@ledgerhq/hw-app-eth';
|
||||||
// tslint:disable:no-implicit-dependencies
|
// tslint:disable:no-implicit-dependencies
|
||||||
import TransportNodeHid from '@ledgerhq/hw-transport-node-hid';
|
import TransportNodeHid from '@ledgerhq/hw-transport-node-hid';
|
||||||
import { Provider } from 'ethereum-types';
|
import { Provider } from 'ethereum-types';
|
||||||
import ProviderEngine = require('web3-provider-engine');
|
|
||||||
import RpcSubprovider = require('web3-provider-engine/subproviders/rpc');
|
|
||||||
|
|
||||||
import { constants } from './constants';
|
import { constants } from './constants';
|
||||||
|
|
||||||
@@ -15,18 +13,14 @@ async function ledgerEthereumNodeJsClientFactoryAsync(): Promise<LedgerEthereumC
|
|||||||
}
|
}
|
||||||
export const providerFactory = {
|
export const providerFactory = {
|
||||||
async getLedgerProviderAsync(): Promise<Provider> {
|
async getLedgerProviderAsync(): Promise<Provider> {
|
||||||
const provider = new ProviderEngine();
|
const provider = new Web3ProviderEngine();
|
||||||
const ledgerWalletConfigs = {
|
const ledgerWalletConfigs = {
|
||||||
networkId: constants.KOVAN_NETWORK_ID,
|
networkId: constants.KOVAN_NETWORK_ID,
|
||||||
ledgerEthereumClientFactoryAsync: ledgerEthereumNodeJsClientFactoryAsync,
|
ledgerEthereumClientFactoryAsync: ledgerEthereumNodeJsClientFactoryAsync,
|
||||||
};
|
};
|
||||||
const ledgerSubprovider = new LedgerSubprovider(ledgerWalletConfigs);
|
const ledgerSubprovider = new LedgerSubprovider(ledgerWalletConfigs);
|
||||||
provider.addProvider(ledgerSubprovider);
|
provider.addProvider(ledgerSubprovider);
|
||||||
provider.addProvider(
|
provider.addProvider(new RPCSubprovider(constants.RPC_URL));
|
||||||
new RpcSubprovider({
|
|
||||||
rpcUrl: constants.RPC_URL,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
provider.start();
|
provider.start();
|
||||||
return provider;
|
return provider;
|
||||||
},
|
},
|
||||||
|
@@ -87,7 +87,6 @@
|
|||||||
"ethereum-types": "^0.0.2",
|
"ethereum-types": "^0.0.2",
|
||||||
"chalk": "^2.3.0",
|
"chalk": "^2.3.0",
|
||||||
"ethereumjs-util": "^5.1.1",
|
"ethereumjs-util": "^5.1.1",
|
||||||
"isomorphic-fetch": "^2.2.1",
|
|
||||||
"lodash": "^4.17.4",
|
"lodash": "^4.17.4",
|
||||||
"mkdirp": "^0.5.1",
|
"mkdirp": "^0.5.1",
|
||||||
"require-from-string": "^2.0.1",
|
"require-from-string": "^2.0.1",
|
||||||
|
@@ -8,11 +8,10 @@ import {
|
|||||||
Resolver,
|
Resolver,
|
||||||
URLResolver,
|
URLResolver,
|
||||||
} from '@0xproject/sol-resolver';
|
} from '@0xproject/sol-resolver';
|
||||||
import { logUtils } from '@0xproject/utils';
|
import { fetchAsync, logUtils } from '@0xproject/utils';
|
||||||
import chalk from 'chalk';
|
import chalk from 'chalk';
|
||||||
import * as ethUtil from 'ethereumjs-util';
|
import * as ethUtil from 'ethereumjs-util';
|
||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
import 'isomorphic-fetch';
|
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import * as requireFromString from 'require-from-string';
|
import * as requireFromString from 'require-from-string';
|
||||||
@@ -149,7 +148,7 @@ export class Compiler {
|
|||||||
} else {
|
} else {
|
||||||
logUtils.log(`Downloading ${fullSolcVersion}...`);
|
logUtils.log(`Downloading ${fullSolcVersion}...`);
|
||||||
const url = `${constants.BASE_COMPILER_URL}${fullSolcVersion}`;
|
const url = `${constants.BASE_COMPILER_URL}${fullSolcVersion}`;
|
||||||
const response = await fetch(url);
|
const response = await fetchAsync(url);
|
||||||
const SUCCESS_STATUS = 200;
|
const SUCCESS_STATUS = 200;
|
||||||
if (response.status !== SUCCESS_STATUS) {
|
if (response.status !== SUCCESS_STATUS) {
|
||||||
throw new Error(`Failed to load ${fullSolcVersion}`);
|
throw new Error(`Failed to load ${fullSolcVersion}`);
|
||||||
|
@@ -55,6 +55,7 @@
|
|||||||
"ethereumjs-util": "^5.1.1",
|
"ethereumjs-util": "^5.1.1",
|
||||||
"ganache-core": "0xProject/ganache-core",
|
"ganache-core": "0xProject/ganache-core",
|
||||||
"hdkey": "^0.7.1",
|
"hdkey": "^0.7.1",
|
||||||
|
"json-rpc-error": "2.0.0",
|
||||||
"lodash": "^4.17.4",
|
"lodash": "^4.17.4",
|
||||||
"semaphore-async-await": "^1.5.1",
|
"semaphore-async-await": "^1.5.1",
|
||||||
"web3-provider-engine": "14.0.6"
|
"web3-provider-engine": "14.0.6"
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
import Eth from '@ledgerhq/hw-app-eth';
|
import Eth from '@ledgerhq/hw-app-eth';
|
||||||
import TransportU2F from '@ledgerhq/hw-transport-u2f';
|
import TransportU2F from '@ledgerhq/hw-transport-u2f';
|
||||||
|
export import Web3ProviderEngine = require('web3-provider-engine');
|
||||||
export { ECSignature } from '@0xproject/types';
|
export { ECSignature } from '@0xproject/types';
|
||||||
|
|
||||||
import { LedgerEthereumClient } from './types';
|
import { LedgerEthereumClient } from './types';
|
||||||
@@ -10,6 +11,7 @@ export { FakeGasEstimateSubprovider } from './subproviders/fake_gas_estimate_sub
|
|||||||
export { SignerSubprovider } from './subproviders/signer';
|
export { SignerSubprovider } from './subproviders/signer';
|
||||||
export { RedundantSubprovider } from './subproviders/redundant_subprovider';
|
export { RedundantSubprovider } from './subproviders/redundant_subprovider';
|
||||||
export { LedgerSubprovider } from './subproviders/ledger';
|
export { LedgerSubprovider } from './subproviders/ledger';
|
||||||
|
export { RPCSubprovider } from './subproviders/rpc_subprovider';
|
||||||
export { GanacheSubprovider } from './subproviders/ganache';
|
export { GanacheSubprovider } from './subproviders/ganache';
|
||||||
export { Subprovider } from './subproviders/subprovider';
|
export { Subprovider } from './subproviders/subprovider';
|
||||||
export { NonceTrackerSubprovider } from './subproviders/nonce_tracker';
|
export { NonceTrackerSubprovider } from './subproviders/nonce_tracker';
|
||||||
|
90
packages/subproviders/src/subproviders/rpc_subprovider.ts
Normal file
90
packages/subproviders/src/subproviders/rpc_subprovider.ts
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
import { assert } from '@0xproject/assert';
|
||||||
|
import { StatusCodes } from '@0xproject/types';
|
||||||
|
import { fetchAsync } from '@0xproject/utils';
|
||||||
|
import { JSONRPCRequestPayload } from 'ethereum-types';
|
||||||
|
import JsonRpcError = require('json-rpc-error');
|
||||||
|
|
||||||
|
import { Callback, ErrorCallback } from '../types';
|
||||||
|
|
||||||
|
import { Subprovider } from './subprovider';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class implements the [web3-provider-engine](https://github.com/MetaMask/provider-engine) subprovider interface.
|
||||||
|
* It forwards on JSON RPC requests to the supplied `rpcUrl` endpoint
|
||||||
|
*/
|
||||||
|
export class RPCSubprovider extends Subprovider {
|
||||||
|
private _rpcUrl: string;
|
||||||
|
private _requestTimeoutMs: number;
|
||||||
|
constructor(rpcUrl: string, requestTimeoutMs: number = 20000) {
|
||||||
|
super();
|
||||||
|
assert.isString('rpcUrl', rpcUrl);
|
||||||
|
assert.isNumber('requestTimeoutMs', requestTimeoutMs);
|
||||||
|
this._rpcUrl = rpcUrl;
|
||||||
|
this._requestTimeoutMs = requestTimeoutMs;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* This method conforms to the web3-provider-engine interface.
|
||||||
|
* It is called internally by the ProviderEngine when it is this subproviders
|
||||||
|
* turn to handle a JSON RPC request.
|
||||||
|
* @param payload JSON RPC payload
|
||||||
|
* @param next Callback to call if this subprovider decides not to handle the request
|
||||||
|
* @param end Callback to call if subprovider handled the request and wants to pass back the request.
|
||||||
|
*/
|
||||||
|
// tslint:disable-next-line:prefer-function-over-method async-suffix
|
||||||
|
public async handleRequest(payload: JSONRPCRequestPayload, _next: Callback, end: ErrorCallback): Promise<void> {
|
||||||
|
const finalPayload = Subprovider._createFinalPayload(payload);
|
||||||
|
const headers = new Headers({
|
||||||
|
Accept: 'application/json',
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
});
|
||||||
|
|
||||||
|
let response;
|
||||||
|
try {
|
||||||
|
response = await fetchAsync(
|
||||||
|
this._rpcUrl,
|
||||||
|
{
|
||||||
|
method: 'POST',
|
||||||
|
headers,
|
||||||
|
body: JSON.stringify(finalPayload),
|
||||||
|
},
|
||||||
|
this._requestTimeoutMs,
|
||||||
|
);
|
||||||
|
} catch (err) {
|
||||||
|
end(new JsonRpcError.InternalError(err));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const text = await response.text();
|
||||||
|
if (!response.ok) {
|
||||||
|
const statusCode = response.status;
|
||||||
|
switch (statusCode) {
|
||||||
|
case StatusCodes.MethodNotAllowed:
|
||||||
|
end(new JsonRpcError.MethodNotFound());
|
||||||
|
return;
|
||||||
|
case StatusCodes.GatewayTimeout:
|
||||||
|
const errMsg =
|
||||||
|
'Gateway timeout. The request took too long to process. This can happen when querying logs over too wide a block range.';
|
||||||
|
const err = new Error(errMsg);
|
||||||
|
end(new JsonRpcError.InternalError(err));
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
end(new JsonRpcError.InternalError(text));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let data;
|
||||||
|
try {
|
||||||
|
data = JSON.parse(text);
|
||||||
|
} catch (err) {
|
||||||
|
end(new JsonRpcError.InternalError(err));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.error) {
|
||||||
|
end(data.error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
end(null, data.result);
|
||||||
|
}
|
||||||
|
}
|
@@ -9,18 +9,7 @@ import { Callback, ErrorCallback, JSONRPCRequestPayloadWithMethod } from '../typ
|
|||||||
export abstract class Subprovider {
|
export abstract class Subprovider {
|
||||||
// tslint:disable-next-line:underscore-private-and-protected
|
// tslint:disable-next-line:underscore-private-and-protected
|
||||||
private engine!: Provider;
|
private engine!: Provider;
|
||||||
// Ported from: https://github.com/MetaMask/provider-engine/blob/master/util/random-id.js
|
protected static _createFinalPayload(
|
||||||
private static _getRandomId(): number {
|
|
||||||
const extraDigits = 3;
|
|
||||||
const baseTen = 10;
|
|
||||||
// 13 time digits
|
|
||||||
const datePart = new Date().getTime() * Math.pow(baseTen, extraDigits);
|
|
||||||
// 3 random digits
|
|
||||||
const extraPart = Math.floor(Math.random() * Math.pow(baseTen, extraDigits));
|
|
||||||
// 16 digits
|
|
||||||
return datePart + extraPart;
|
|
||||||
}
|
|
||||||
private static _createFinalPayload(
|
|
||||||
payload: Partial<JSONRPCRequestPayloadWithMethod>,
|
payload: Partial<JSONRPCRequestPayloadWithMethod>,
|
||||||
): Partial<JSONRPCRequestPayloadWithMethod> {
|
): Partial<JSONRPCRequestPayloadWithMethod> {
|
||||||
const finalPayload = {
|
const finalPayload = {
|
||||||
@@ -32,6 +21,17 @@ export abstract class Subprovider {
|
|||||||
};
|
};
|
||||||
return finalPayload;
|
return finalPayload;
|
||||||
}
|
}
|
||||||
|
// Ported from: https://github.com/MetaMask/provider-engine/blob/master/util/random-id.js
|
||||||
|
private static _getRandomId(): number {
|
||||||
|
const extraDigits = 3;
|
||||||
|
const baseTen = 10;
|
||||||
|
// 13 time digits
|
||||||
|
const datePart = new Date().getTime() * Math.pow(baseTen, extraDigits);
|
||||||
|
// 3 random digits
|
||||||
|
const extraPart = Math.floor(Math.random() * Math.pow(baseTen, extraDigits));
|
||||||
|
// 16 digits
|
||||||
|
return datePart + extraPart;
|
||||||
|
}
|
||||||
// tslint:disable-next-line:async-suffix
|
// tslint:disable-next-line:async-suffix
|
||||||
public abstract async handleRequest(
|
public abstract async handleRequest(
|
||||||
payload: JSONRPCRequestPayload,
|
payload: JSONRPCRequestPayload,
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
import ProviderEngine = require('web3-provider-engine');
|
import Web3ProviderEngine = require('web3-provider-engine');
|
||||||
|
|
||||||
import { Subprovider } from '../subproviders/subprovider';
|
import { Subprovider } from '../subproviders/subprovider';
|
||||||
|
|
||||||
@@ -7,7 +7,7 @@ import { Subprovider } from '../subproviders/subprovider';
|
|||||||
* @param provider Given provider
|
* @param provider Given provider
|
||||||
* @param subprovider Subprovider to prepend
|
* @param subprovider Subprovider to prepend
|
||||||
*/
|
*/
|
||||||
export function prependSubprovider(provider: ProviderEngine, subprovider: Subprovider): void {
|
export function prependSubprovider(provider: Web3ProviderEngine, subprovider: Subprovider): void {
|
||||||
subprovider.setEngine(provider);
|
subprovider.setEngine(provider);
|
||||||
// HACK: We use implementation details of provider engine here
|
// HACK: We use implementation details of provider engine here
|
||||||
// https://github.com/MetaMask/provider-engine/blob/master/index.js#L68
|
// https://github.com/MetaMask/provider-engine/blob/master/index.js#L68
|
||||||
|
@@ -7,10 +7,8 @@ import TransportNodeHid from '@ledgerhq/hw-transport-node-hid';
|
|||||||
import * as chai from 'chai';
|
import * as chai from 'chai';
|
||||||
import { JSONRPCResponsePayload } from 'ethereum-types';
|
import { JSONRPCResponsePayload } from 'ethereum-types';
|
||||||
import * as ethUtils from 'ethereumjs-util';
|
import * as ethUtils from 'ethereumjs-util';
|
||||||
import Web3ProviderEngine = require('web3-provider-engine');
|
|
||||||
import RpcSubprovider = require('web3-provider-engine/subproviders/rpc');
|
|
||||||
|
|
||||||
import { LedgerSubprovider } from '../../src';
|
import { LedgerSubprovider, RPCSubprovider, Web3ProviderEngine } from '../../src';
|
||||||
import { LedgerEthereumClient } from '../../src/types';
|
import { LedgerEthereumClient } from '../../src/types';
|
||||||
import { chaiSetup } from '../chai_setup';
|
import { chaiSetup } from '../chai_setup';
|
||||||
import { fixtureData } from '../utils/fixture_data';
|
import { fixtureData } from '../utils/fixture_data';
|
||||||
@@ -86,9 +84,7 @@ describe('LedgerSubprovider', () => {
|
|||||||
before(() => {
|
before(() => {
|
||||||
ledgerProvider = new Web3ProviderEngine();
|
ledgerProvider = new Web3ProviderEngine();
|
||||||
ledgerProvider.addProvider(ledgerSubprovider);
|
ledgerProvider.addProvider(ledgerSubprovider);
|
||||||
const httpProvider = new RpcSubprovider({
|
const httpProvider = new RPCSubprovider('http://localhost:8545');
|
||||||
rpcUrl: 'http://localhost:8545',
|
|
||||||
});
|
|
||||||
ledgerProvider.addProvider(httpProvider);
|
ledgerProvider.addProvider(httpProvider);
|
||||||
ledgerProvider.start();
|
ledgerProvider.start();
|
||||||
|
|
||||||
|
@@ -2,9 +2,8 @@ import * as chai from 'chai';
|
|||||||
import * as lightwallet from 'eth-lightwallet';
|
import * as lightwallet from 'eth-lightwallet';
|
||||||
import { JSONRPCResponsePayload } from 'ethereum-types';
|
import { JSONRPCResponsePayload } from 'ethereum-types';
|
||||||
import * as ethUtils from 'ethereumjs-util';
|
import * as ethUtils from 'ethereumjs-util';
|
||||||
import Web3ProviderEngine = require('web3-provider-engine');
|
|
||||||
|
|
||||||
import { EthLightwalletSubprovider } from '../../src';
|
import { EthLightwalletSubprovider, Web3ProviderEngine } from '../../src';
|
||||||
import { DoneCallback } from '../../src/types';
|
import { DoneCallback } from '../../src/types';
|
||||||
import { chaiSetup } from '../chai_setup';
|
import { chaiSetup } from '../chai_setup';
|
||||||
import { fixtureData } from '../utils/fixture_data';
|
import { fixtureData } from '../utils/fixture_data';
|
||||||
|
@@ -2,9 +2,8 @@ import * as chai from 'chai';
|
|||||||
import { JSONRPCResponsePayload } from 'ethereum-types';
|
import { JSONRPCResponsePayload } from 'ethereum-types';
|
||||||
import * as ethUtils from 'ethereumjs-util';
|
import * as ethUtils from 'ethereumjs-util';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
import Web3ProviderEngine = require('web3-provider-engine');
|
|
||||||
|
|
||||||
import { LedgerSubprovider } from '../../src';
|
import { LedgerSubprovider, Web3ProviderEngine } from '../../src';
|
||||||
import {
|
import {
|
||||||
DoneCallback,
|
DoneCallback,
|
||||||
LedgerCommunicationClient,
|
LedgerCommunicationClient,
|
||||||
|
@@ -1,9 +1,8 @@
|
|||||||
import * as chai from 'chai';
|
import * as chai from 'chai';
|
||||||
import { JSONRPCResponsePayload } from 'ethereum-types';
|
import { JSONRPCResponsePayload } from 'ethereum-types';
|
||||||
import * as ethUtils from 'ethereumjs-util';
|
import * as ethUtils from 'ethereumjs-util';
|
||||||
import Web3ProviderEngine = require('web3-provider-engine');
|
|
||||||
|
|
||||||
import { GanacheSubprovider, MnemonicWalletSubprovider } from '../../src/';
|
import { GanacheSubprovider, MnemonicWalletSubprovider, Web3ProviderEngine } from '../../src/';
|
||||||
import { DoneCallback, WalletSubproviderErrors } from '../../src/types';
|
import { DoneCallback, WalletSubproviderErrors } from '../../src/types';
|
||||||
import { chaiSetup } from '../chai_setup';
|
import { chaiSetup } from '../chai_setup';
|
||||||
import { fixtureData } from '../utils/fixture_data';
|
import { fixtureData } from '../utils/fixture_data';
|
||||||
|
@@ -1,11 +1,10 @@
|
|||||||
import * as chai from 'chai';
|
import * as chai from 'chai';
|
||||||
import Web3ProviderEngine = require('web3-provider-engine');
|
|
||||||
import FixtureSubprovider = require('web3-provider-engine/subproviders/fixture');
|
import FixtureSubprovider = require('web3-provider-engine/subproviders/fixture');
|
||||||
|
|
||||||
import { promisify } from '@0xproject/utils';
|
import { promisify } from '@0xproject/utils';
|
||||||
import EthereumTx = require('ethereumjs-tx');
|
import EthereumTx = require('ethereumjs-tx');
|
||||||
|
|
||||||
import { NonceTrackerSubprovider } from '../../src';
|
import { NonceTrackerSubprovider, Web3ProviderEngine } from '../../src';
|
||||||
import { chaiSetup } from '../chai_setup';
|
import { chaiSetup } from '../chai_setup';
|
||||||
|
|
||||||
const expect = chai.expect;
|
const expect = chai.expect;
|
||||||
|
@@ -1,9 +1,8 @@
|
|||||||
import * as chai from 'chai';
|
import * as chai from 'chai';
|
||||||
import { JSONRPCResponsePayload } from 'ethereum-types';
|
import { JSONRPCResponsePayload } from 'ethereum-types';
|
||||||
import * as ethUtils from 'ethereumjs-util';
|
import * as ethUtils from 'ethereumjs-util';
|
||||||
import Web3ProviderEngine = require('web3-provider-engine');
|
|
||||||
|
|
||||||
import { GanacheSubprovider, PrivateKeyWalletSubprovider } from '../../src/';
|
import { GanacheSubprovider, PrivateKeyWalletSubprovider, Web3ProviderEngine } from '../../src/';
|
||||||
import { DoneCallback, WalletSubproviderErrors } from '../../src/types';
|
import { DoneCallback, WalletSubproviderErrors } from '../../src/types';
|
||||||
import { chaiSetup } from '../chai_setup';
|
import { chaiSetup } from '../chai_setup';
|
||||||
import { fixtureData } from '../utils/fixture_data';
|
import { fixtureData } from '../utils/fixture_data';
|
||||||
|
@@ -2,10 +2,8 @@ import { DoneCallback } from '@0xproject/types';
|
|||||||
import * as chai from 'chai';
|
import * as chai from 'chai';
|
||||||
import { JSONRPCResponsePayload } from 'ethereum-types';
|
import { JSONRPCResponsePayload } from 'ethereum-types';
|
||||||
import * as Sinon from 'sinon';
|
import * as Sinon from 'sinon';
|
||||||
import Web3ProviderEngine = require('web3-provider-engine');
|
|
||||||
import RpcSubprovider = require('web3-provider-engine/subproviders/rpc');
|
|
||||||
|
|
||||||
import { RedundantSubprovider } from '../../src';
|
import { RedundantSubprovider, RPCSubprovider, Web3ProviderEngine } from '../../src';
|
||||||
import { Subprovider } from '../../src/subproviders/subprovider';
|
import { Subprovider } from '../../src/subproviders/subprovider';
|
||||||
import { chaiSetup } from '../chai_setup';
|
import { chaiSetup } from '../chai_setup';
|
||||||
import { ganacheSubprovider } from '../utils/ganache_subprovider';
|
import { ganacheSubprovider } from '../utils/ganache_subprovider';
|
||||||
@@ -39,9 +37,7 @@ describe('RedundantSubprovider', () => {
|
|||||||
});
|
});
|
||||||
it('succeeds when supplied at least one healthy endpoint', (done: DoneCallback) => {
|
it('succeeds when supplied at least one healthy endpoint', (done: DoneCallback) => {
|
||||||
provider = new Web3ProviderEngine();
|
provider = new Web3ProviderEngine();
|
||||||
const nonExistentSubprovider = new RpcSubprovider({
|
const nonExistentSubprovider = new RPCSubprovider('http://does-not-exist:3000');
|
||||||
rpcUrl: 'http://does-not-exist:3000',
|
|
||||||
});
|
|
||||||
const handleRequestStub = Sinon.stub(nonExistentSubprovider, 'handleRequest').throws(
|
const handleRequestStub = Sinon.stub(nonExistentSubprovider, 'handleRequest').throws(
|
||||||
new Error('REQUEST_FAILED'),
|
new Error('REQUEST_FAILED'),
|
||||||
);
|
);
|
||||||
|
@@ -18,7 +18,7 @@
|
|||||||
"author": "Fabio Berger",
|
"author": "Fabio Berger",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"0x.js": "^0.38.0",
|
"0x.js": "0.38.4",
|
||||||
"@0xproject/subproviders": "^0.10.5",
|
"@0xproject/subproviders": "^0.10.5",
|
||||||
"@0xproject/web3-wrapper": "^0.7.2",
|
"@0xproject/web3-wrapper": "^0.7.2",
|
||||||
"@0xproject/typescript-typings": "^0.4.2",
|
"@0xproject/typescript-typings": "^0.4.2",
|
||||||
@@ -28,8 +28,7 @@
|
|||||||
"ethereumjs-util": "^5.1.1",
|
"ethereumjs-util": "^5.1.1",
|
||||||
"express": "^4.15.2",
|
"express": "^4.15.2",
|
||||||
"lodash": "^4.17.4",
|
"lodash": "^4.17.4",
|
||||||
"rollbar": "^0.6.5",
|
"rollbar": "^0.6.5"
|
||||||
"web3-provider-engine": "14.0.6"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@0xproject/tslint-config": "^0.4.21",
|
"@0xproject/tslint-config": "^0.4.21",
|
||||||
|
@@ -5,9 +5,12 @@ import { Provider } from 'ethereum-types';
|
|||||||
import * as express from 'express';
|
import * as express from 'express';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
|
|
||||||
import { NonceTrackerSubprovider, PrivateKeyWalletSubprovider } from '@0xproject/subproviders';
|
import {
|
||||||
import ProviderEngine = require('web3-provider-engine');
|
NonceTrackerSubprovider,
|
||||||
import RpcSubprovider = require('web3-provider-engine/subproviders/rpc');
|
PrivateKeyWalletSubprovider,
|
||||||
|
RPCSubprovider,
|
||||||
|
Web3ProviderEngine,
|
||||||
|
} from '@0xproject/subproviders';
|
||||||
|
|
||||||
import { configs } from './configs';
|
import { configs } from './configs';
|
||||||
import { constants } from './constants';
|
import { constants } from './constants';
|
||||||
@@ -39,14 +42,10 @@ export class Handler {
|
|||||||
if (_.isUndefined(configs.DISPENSER_PRIVATE_KEY)) {
|
if (_.isUndefined(configs.DISPENSER_PRIVATE_KEY)) {
|
||||||
throw new Error('Dispenser Private key not found');
|
throw new Error('Dispenser Private key not found');
|
||||||
}
|
}
|
||||||
const engine = new ProviderEngine();
|
const engine = new Web3ProviderEngine();
|
||||||
engine.addProvider(new NonceTrackerSubprovider());
|
engine.addProvider(new NonceTrackerSubprovider());
|
||||||
engine.addProvider(new PrivateKeyWalletSubprovider(configs.DISPENSER_PRIVATE_KEY));
|
engine.addProvider(new PrivateKeyWalletSubprovider(configs.DISPENSER_PRIVATE_KEY));
|
||||||
engine.addProvider(
|
engine.addProvider(new RPCSubprovider(rpcUrl));
|
||||||
new RpcSubprovider({
|
|
||||||
rpcUrl,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
engine.start();
|
engine.start();
|
||||||
return engine;
|
return engine;
|
||||||
}
|
}
|
||||||
|
@@ -221,3 +221,11 @@ export enum RevertReason {
|
|||||||
ValueGreaterThanZero = 'VALUE_GREATER_THAN_ZERO',
|
ValueGreaterThanZero = 'VALUE_GREATER_THAN_ZERO',
|
||||||
InvalidMsgValue = 'INVALID_MSG_VALUE',
|
InvalidMsgValue = 'INVALID_MSG_VALUE',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum StatusCodes {
|
||||||
|
Success = 200,
|
||||||
|
NotFound = 404,
|
||||||
|
InternalError = 500,
|
||||||
|
MethodNotAllowed = 405,
|
||||||
|
GatewayTimeout = 504,
|
||||||
|
}
|
||||||
|
3
packages/typescript-typings/types/detect-node/index.d.ts
vendored
Normal file
3
packages/typescript-typings/types/detect-node/index.d.ts
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
declare module 'detect-node' {
|
||||||
|
export const isNode: boolean;
|
||||||
|
}
|
8
packages/typescript-typings/types/json-rpc-error/index.d.ts
vendored
Normal file
8
packages/typescript-typings/types/json-rpc-error/index.d.ts
vendored
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
declare module 'json-rpc-error' {
|
||||||
|
export class InternalError extends Error {
|
||||||
|
constructor(err: Error | string);
|
||||||
|
}
|
||||||
|
export class MethodNotFound extends Error {
|
||||||
|
constructor();
|
||||||
|
}
|
||||||
|
}
|
@@ -35,14 +35,15 @@
|
|||||||
"typescript": "2.7.1"
|
"typescript": "2.7.1"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"ethereum-types": "^0.0.2",
|
"@0xproject/types": "^1.0.0",
|
||||||
"@0xproject/typescript-typings": "^0.4.2",
|
"@0xproject/typescript-typings": "^0.4.2",
|
||||||
"@types/node": "^8.0.53",
|
"@types/node": "^8.0.53",
|
||||||
"ethereumjs-util": "^5.1.1",
|
|
||||||
"bignumber.js": "~4.1.0",
|
"bignumber.js": "~4.1.0",
|
||||||
|
"detect-node": "2.0.3",
|
||||||
"ethereum-types": "^0.0.2",
|
"ethereum-types": "^0.0.2",
|
||||||
"ethereumjs-util": "^5.1.1",
|
"ethereumjs-util": "^5.1.1",
|
||||||
"ethers": "3.0.22",
|
"ethers": "3.0.22",
|
||||||
|
"isomorphic-fetch": "^2.2.1",
|
||||||
"js-sha3": "^0.7.0",
|
"js-sha3": "^0.7.0",
|
||||||
"lodash": "^4.17.4"
|
"lodash": "^4.17.4"
|
||||||
},
|
},
|
||||||
|
37
packages/utils/src/fetchAsync.ts
Normal file
37
packages/utils/src/fetchAsync.ts
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
import isNode = require('detect-node');
|
||||||
|
import 'isomorphic-fetch';
|
||||||
|
|
||||||
|
export const fetchAsync = async (
|
||||||
|
endpoint: string,
|
||||||
|
options: RequestInit = {},
|
||||||
|
timeoutMs: number = 20000,
|
||||||
|
): Promise<Response> => {
|
||||||
|
if (options.signal || (options as any).timeout) {
|
||||||
|
throw new Error(
|
||||||
|
'Cannot call fetchAsync with options.signal or options.timeout. To set a timeout, please use the supplied "timeoutMs" parameter.',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
let optionsWithAbortParam;
|
||||||
|
if (!isNode) {
|
||||||
|
const controller = new AbortController();
|
||||||
|
const signal = controller.signal;
|
||||||
|
setTimeout(() => {
|
||||||
|
controller.abort();
|
||||||
|
}, timeoutMs);
|
||||||
|
optionsWithAbortParam = {
|
||||||
|
signal,
|
||||||
|
...options,
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
// HACK: the `timeout` param only exists in `node-fetch`, and not on the `isomorphic-fetch`
|
||||||
|
// `RequestInit` type. Since `isomorphic-fetch` conditionally wraps `node-fetch` when the
|
||||||
|
// execution environment is `Node.js`, we need to cast it to `any` in that scenario.
|
||||||
|
optionsWithAbortParam = {
|
||||||
|
timeout: timeoutMs,
|
||||||
|
...options,
|
||||||
|
} as any;
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await fetch(endpoint, optionsWithAbortParam);
|
||||||
|
return response;
|
||||||
|
};
|
@@ -8,3 +8,4 @@ export { logUtils } from './log_utils';
|
|||||||
export { abiUtils } from './abi_utils';
|
export { abiUtils } from './abi_utils';
|
||||||
export { NULL_BYTES } from './constants';
|
export { NULL_BYTES } from './constants';
|
||||||
export { errorUtils } from './error_utils';
|
export { errorUtils } from './error_utils';
|
||||||
|
export { fetchAsync } from './fetchAsync';
|
||||||
|
@@ -49,7 +49,6 @@
|
|||||||
"react-copy-to-clipboard": "^4.2.3",
|
"react-copy-to-clipboard": "^4.2.3",
|
||||||
"react-document-title": "^2.0.3",
|
"react-document-title": "^2.0.3",
|
||||||
"react-dom": "15.6.1",
|
"react-dom": "15.6.1",
|
||||||
"react-ga": "^2.4.1",
|
|
||||||
"react-popper": "^1.0.0-beta.6",
|
"react-popper": "^1.0.0-beta.6",
|
||||||
"react-redux": "^5.0.3",
|
"react-redux": "^5.0.3",
|
||||||
"react-router-dom": "^4.1.1",
|
"react-router-dom": "^4.1.1",
|
||||||
@@ -63,7 +62,6 @@
|
|||||||
"thenby": "^1.2.3",
|
"thenby": "^1.2.3",
|
||||||
"truffle-contract": "2.0.1",
|
"truffle-contract": "2.0.1",
|
||||||
"web3-provider-engine": "14.0.6",
|
"web3-provider-engine": "14.0.6",
|
||||||
"whatwg-fetch": "^2.0.3",
|
|
||||||
"xml-js": "^1.6.4"
|
"xml-js": "^1.6.4"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
@@ -23,6 +23,12 @@
|
|||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body style="margin: 0px; min-width: 355px;">
|
<body style="margin: 0px; min-width: 355px;">
|
||||||
|
<!-- Heap SDK -->
|
||||||
|
<script type="text/javascript">
|
||||||
|
window.heap = window.heap || [], heap.load = function (e, t) { window.heap.appid = e, window.heap.config = t = t || {}; var r = t.forceSSL || "https:" === document.location.protocol, a = document.createElement("script"); a.type = "text/javascript", a.async = !0, a.src = (r ? "https:" : "http:") + "//cdn.heapanalytics.com/js/heap-" + e + ".js"; var n = document.getElementsByTagName("script")[0]; n.parentNode.insertBefore(a, n); for (var o = function (e) { return function () { heap.push([e].concat(Array.prototype.slice.call(arguments, 0))) } }, p = ["addEventProperties", "addUserProperties", "clearEventProperties", "identify", "resetIdentity", "removeEventProperty", "setEventProperties", "track", "unsetEventProperty"], c = 0; c < p.length; c++)heap[p[c]] = o(p[c]) };
|
||||||
|
heap.load("410099666");
|
||||||
|
</script>
|
||||||
|
<!-- End Heap SDK -->
|
||||||
<!-- Global site tag (gtag.js) - Google Analytics -->
|
<!-- Global site tag (gtag.js) - Google Analytics -->
|
||||||
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-98720122-1"></script>
|
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-98720122-1"></script>
|
||||||
<script>
|
<script>
|
||||||
|
@@ -15,8 +15,9 @@ import {
|
|||||||
ledgerEthereumBrowserClientFactoryAsync,
|
ledgerEthereumBrowserClientFactoryAsync,
|
||||||
LedgerSubprovider,
|
LedgerSubprovider,
|
||||||
RedundantSubprovider,
|
RedundantSubprovider,
|
||||||
|
RPCSubprovider,
|
||||||
SignerSubprovider,
|
SignerSubprovider,
|
||||||
Subprovider,
|
Web3ProviderEngine,
|
||||||
} from '@0xproject/subproviders';
|
} from '@0xproject/subproviders';
|
||||||
import {
|
import {
|
||||||
BlockParam,
|
BlockParam,
|
||||||
@@ -60,9 +61,7 @@ import { configs } from 'ts/utils/configs';
|
|||||||
import { constants } from 'ts/utils/constants';
|
import { constants } from 'ts/utils/constants';
|
||||||
import { errorReporter } from 'ts/utils/error_reporter';
|
import { errorReporter } from 'ts/utils/error_reporter';
|
||||||
import { utils } from 'ts/utils/utils';
|
import { utils } from 'ts/utils/utils';
|
||||||
import ProviderEngine = require('web3-provider-engine');
|
|
||||||
import FilterSubprovider = require('web3-provider-engine/subproviders/filters');
|
import FilterSubprovider = require('web3-provider-engine/subproviders/filters');
|
||||||
import RpcSubprovider = require('web3-provider-engine/subproviders/rpc');
|
|
||||||
|
|
||||||
import * as MintableArtifacts from '../contracts/Mintable.json';
|
import * as MintableArtifacts from '../contracts/Mintable.json';
|
||||||
|
|
||||||
@@ -148,7 +147,7 @@ export class Blockchain {
|
|||||||
if (!isU2FSupported) {
|
if (!isU2FSupported) {
|
||||||
throw new Error('Cannot update providerType to LEDGER without U2F support');
|
throw new Error('Cannot update providerType to LEDGER without U2F support');
|
||||||
}
|
}
|
||||||
const provider = new ProviderEngine();
|
const provider = new Web3ProviderEngine();
|
||||||
const ledgerWalletConfigs = {
|
const ledgerWalletConfigs = {
|
||||||
networkId: networkIdIfExists,
|
networkId: networkIdIfExists,
|
||||||
ledgerEthereumClientFactoryAsync: ledgerEthereumBrowserClientFactoryAsync,
|
ledgerEthereumClientFactoryAsync: ledgerEthereumBrowserClientFactoryAsync,
|
||||||
@@ -157,25 +156,21 @@ export class Blockchain {
|
|||||||
provider.addProvider(ledgerSubprovider);
|
provider.addProvider(ledgerSubprovider);
|
||||||
provider.addProvider(new FilterSubprovider());
|
provider.addProvider(new FilterSubprovider());
|
||||||
const rpcSubproviders = _.map(configs.PUBLIC_NODE_URLS_BY_NETWORK_ID[networkIdIfExists], publicNodeUrl => {
|
const rpcSubproviders = _.map(configs.PUBLIC_NODE_URLS_BY_NETWORK_ID[networkIdIfExists], publicNodeUrl => {
|
||||||
return new RpcSubprovider({
|
return new RPCSubprovider(publicNodeUrl);
|
||||||
rpcUrl: publicNodeUrl,
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
provider.addProvider(new RedundantSubprovider(rpcSubproviders as Subprovider[]));
|
provider.addProvider(new RedundantSubprovider(rpcSubproviders));
|
||||||
provider.start();
|
provider.start();
|
||||||
return [provider, ledgerSubprovider];
|
return [provider, ledgerSubprovider];
|
||||||
} else if (doesInjectedWeb3Exist && isPublicNodeAvailableForNetworkId) {
|
} else if (doesInjectedWeb3Exist && isPublicNodeAvailableForNetworkId) {
|
||||||
// We catch all requests involving a users account and send it to the injectedWeb3
|
// We catch all requests involving a users account and send it to the injectedWeb3
|
||||||
// instance. All other requests go to the public hosted node.
|
// instance. All other requests go to the public hosted node.
|
||||||
const provider = new ProviderEngine();
|
const provider = new Web3ProviderEngine();
|
||||||
provider.addProvider(new SignerSubprovider(injectedWeb3.currentProvider));
|
provider.addProvider(new SignerSubprovider(injectedWeb3.currentProvider));
|
||||||
provider.addProvider(new FilterSubprovider());
|
provider.addProvider(new FilterSubprovider());
|
||||||
const rpcSubproviders = _.map(publicNodeUrlsIfExistsForNetworkId, publicNodeUrl => {
|
const rpcSubproviders = _.map(publicNodeUrlsIfExistsForNetworkId, publicNodeUrl => {
|
||||||
return new RpcSubprovider({
|
return new RPCSubprovider(publicNodeUrl);
|
||||||
rpcUrl: publicNodeUrl,
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
provider.addProvider(new RedundantSubprovider(rpcSubproviders as Subprovider[]));
|
provider.addProvider(new RedundantSubprovider(rpcSubproviders));
|
||||||
provider.start();
|
provider.start();
|
||||||
return [provider, undefined];
|
return [provider, undefined];
|
||||||
} else if (doesInjectedWeb3Exist) {
|
} else if (doesInjectedWeb3Exist) {
|
||||||
@@ -185,15 +180,13 @@ export class Blockchain {
|
|||||||
// If no injectedWeb3 instance, all requests fallback to our public hosted mainnet/testnet node
|
// If no injectedWeb3 instance, all requests fallback to our public hosted mainnet/testnet node
|
||||||
// We do this so that users can still browse the 0x Portal DApp even if they do not have web3
|
// We do this so that users can still browse the 0x Portal DApp even if they do not have web3
|
||||||
// injected into their browser.
|
// injected into their browser.
|
||||||
const provider = new ProviderEngine();
|
const provider = new Web3ProviderEngine();
|
||||||
provider.addProvider(new FilterSubprovider());
|
provider.addProvider(new FilterSubprovider());
|
||||||
const networkId = constants.NETWORK_ID_MAINNET;
|
const networkId = constants.NETWORK_ID_MAINNET;
|
||||||
const rpcSubproviders = _.map(configs.PUBLIC_NODE_URLS_BY_NETWORK_ID[networkId], publicNodeUrl => {
|
const rpcSubproviders = _.map(configs.PUBLIC_NODE_URLS_BY_NETWORK_ID[networkId], publicNodeUrl => {
|
||||||
return new RpcSubprovider({
|
return new RPCSubprovider(publicNodeUrl);
|
||||||
rpcUrl: publicNodeUrl,
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
provider.addProvider(new RedundantSubprovider(rpcSubproviders as Subprovider[]));
|
provider.addProvider(new RedundantSubprovider(rpcSubproviders));
|
||||||
provider.start();
|
provider.start();
|
||||||
return [provider, undefined];
|
return [provider, undefined];
|
||||||
}
|
}
|
||||||
@@ -794,7 +787,7 @@ export class Blockchain {
|
|||||||
return tokenByAddress;
|
return tokenByAddress;
|
||||||
}
|
}
|
||||||
private async _onPageLoadInitFireAndForgetAsync(): Promise<void> {
|
private async _onPageLoadInitFireAndForgetAsync(): Promise<void> {
|
||||||
await utils.onPageLoadAsync(); // wait for page to load
|
await utils.onPageLoadPromise; // wait for page to load
|
||||||
const networkIdIfExists = await Blockchain._getInjectedWeb3ProviderNetworkIdIfExistsAsync();
|
const networkIdIfExists = await Blockchain._getInjectedWeb3ProviderNetworkIdIfExistsAsync();
|
||||||
this.networkId = !_.isUndefined(networkIdIfExists) ? networkIdIfExists : constants.NETWORK_ID_MAINNET;
|
this.networkId = !_.isUndefined(networkIdIfExists) ? networkIdIfExists : constants.NETWORK_ID_MAINNET;
|
||||||
const injectedWeb3IfExists = Blockchain._getInjectedWeb3();
|
const injectedWeb3IfExists = Blockchain._getInjectedWeb3();
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
import { getOrderHashHex, isValidSignature } from '@0xproject/order-utils';
|
import { getOrderHashHex, isValidSignature } from '@0xproject/order-utils';
|
||||||
import { colors, constants as sharedConstants } from '@0xproject/react-shared';
|
import { colors } from '@0xproject/react-shared';
|
||||||
import { Order as ZeroExOrder } from '@0xproject/types';
|
import { Order as ZeroExOrder } from '@0xproject/types';
|
||||||
import { BigNumber, logUtils } from '@0xproject/utils';
|
import { BigNumber, logUtils } from '@0xproject/utils';
|
||||||
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
||||||
@@ -506,6 +506,10 @@ export class FillOrder extends React.Component<FillOrderProps, FillOrderState> {
|
|||||||
|
|
||||||
await this._checkForUntrackedTokensAndAskToAddAsync();
|
await this._checkForUntrackedTokensAndAskToAddAsync();
|
||||||
}
|
}
|
||||||
|
private _trackOrderEvent(eventName: string): void {
|
||||||
|
const parsedOrder = this.state.parsedOrder;
|
||||||
|
analytics.trackOrderEvent(eventName, parsedOrder);
|
||||||
|
}
|
||||||
private async _onFillOrderClickFireAndForgetAsync(): Promise<void> {
|
private async _onFillOrderClickFireAndForgetAsync(): Promise<void> {
|
||||||
if (this.props.blockchainErr !== BlockchainErrs.NoError || _.isEmpty(this.props.userAddress)) {
|
if (this.props.blockchainErr !== BlockchainErrs.NoError || _.isEmpty(this.props.userAddress)) {
|
||||||
this.props.dispatcher.updateShouldBlockchainErrDialogBeOpen(true);
|
this.props.dispatcher.updateShouldBlockchainErrDialogBeOpen(true);
|
||||||
@@ -552,14 +556,12 @@ export class FillOrder extends React.Component<FillOrderProps, FillOrderState> {
|
|||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const networkName = sharedConstants.NETWORK_NAME_BY_ID[this.props.networkId];
|
|
||||||
const eventLabel = `${parsedOrder.metadata.takerToken.symbol}-${networkName}`;
|
|
||||||
try {
|
try {
|
||||||
const orderFilledAmount: BigNumber = await this.props.blockchain.fillOrderAsync(
|
const orderFilledAmount: BigNumber = await this.props.blockchain.fillOrderAsync(
|
||||||
signedOrder,
|
signedOrder,
|
||||||
this.props.orderFillAmount,
|
this.props.orderFillAmount,
|
||||||
);
|
);
|
||||||
analytics.logEvent('Portal', 'Fill Order Success', eventLabel, parsedOrder.signedOrder.takerTokenAmount);
|
this._trackOrderEvent('Fill Order Success');
|
||||||
// After fill completes, let's force fetch the token balances
|
// After fill completes, let's force fetch the token balances
|
||||||
this.props.dispatcher.forceTokenStateRefetch();
|
this.props.dispatcher.forceTokenStateRefetch();
|
||||||
this.setState({
|
this.setState({
|
||||||
@@ -573,7 +575,7 @@ export class FillOrder extends React.Component<FillOrderProps, FillOrderState> {
|
|||||||
this.setState({
|
this.setState({
|
||||||
isFilling: false,
|
isFilling: false,
|
||||||
});
|
});
|
||||||
analytics.logEvent('Portal', 'Fill Order Failure', eventLabel, parsedOrder.signedOrder.takerTokenAmount);
|
this._trackOrderEvent('Fill Order Failure');
|
||||||
const errMsg = `${err}`;
|
const errMsg = `${err}`;
|
||||||
if (utils.didUserDenyWeb3Request(errMsg)) {
|
if (utils.didUserDenyWeb3Request(errMsg)) {
|
||||||
return;
|
return;
|
||||||
@@ -628,8 +630,6 @@ export class FillOrder extends React.Component<FillOrderProps, FillOrderState> {
|
|||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const networkName = sharedConstants.NETWORK_NAME_BY_ID[this.props.networkId];
|
|
||||||
const eventLabel = `${parsedOrder.metadata.makerToken.symbol}-${networkName}`;
|
|
||||||
try {
|
try {
|
||||||
await this.props.blockchain.cancelOrderAsync(signedOrder, availableTakerTokenAmount);
|
await this.props.blockchain.cancelOrderAsync(signedOrder, availableTakerTokenAmount);
|
||||||
this.setState({
|
this.setState({
|
||||||
@@ -638,7 +638,7 @@ export class FillOrder extends React.Component<FillOrderProps, FillOrderState> {
|
|||||||
globalErrMsg: '',
|
globalErrMsg: '',
|
||||||
unavailableTakerAmount: takerTokenAmount,
|
unavailableTakerAmount: takerTokenAmount,
|
||||||
});
|
});
|
||||||
analytics.logEvent('Portal', 'Cancel Order Success', eventLabel, parsedOrder.signedOrder.makerTokenAmount);
|
this._trackOrderEvent('Cancel Order Success');
|
||||||
return;
|
return;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
this.setState({
|
this.setState({
|
||||||
@@ -648,7 +648,7 @@ export class FillOrder extends React.Component<FillOrderProps, FillOrderState> {
|
|||||||
if (utils.didUserDenyWeb3Request(errMsg)) {
|
if (utils.didUserDenyWeb3Request(errMsg)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
analytics.logEvent('Portal', 'Cancel Order Failure', eventLabel, parsedOrder.signedOrder.makerTokenAmount);
|
this._trackOrderEvent('Cancel Order Failure');
|
||||||
globalErrMsg = 'Failed to cancel order, please refresh and try again';
|
globalErrMsg = 'Failed to cancel order, please refresh and try again';
|
||||||
logUtils.log(`${err}`);
|
logUtils.log(`${err}`);
|
||||||
this.setState({
|
this.setState({
|
||||||
|
@@ -6,6 +6,7 @@ import { Button } from 'ts/components/ui/button';
|
|||||||
import { Container } from 'ts/components/ui/container';
|
import { Container } from 'ts/components/ui/container';
|
||||||
import { Input } from 'ts/components/ui/input';
|
import { Input } from 'ts/components/ui/input';
|
||||||
import { Text } from 'ts/components/ui/text';
|
import { Text } from 'ts/components/ui/text';
|
||||||
|
import { analytics } from 'ts/utils/analytics';
|
||||||
import { backendClient } from 'ts/utils/backend_client';
|
import { backendClient } from 'ts/utils/backend_client';
|
||||||
|
|
||||||
export interface SubscribeFormProps {}
|
export interface SubscribeFormProps {}
|
||||||
@@ -112,6 +113,9 @@ export class SubscribeForm extends React.Component<SubscribeFormProps, Subscribe
|
|||||||
try {
|
try {
|
||||||
const response = await backendClient.subscribeToNewsletterAsync(this.state.emailText);
|
const response = await backendClient.subscribeToNewsletterAsync(this.state.emailText);
|
||||||
const status = response.status === 200 ? SubscribeFormStatus.Success : SubscribeFormStatus.Error;
|
const status = response.status === 200 ? SubscribeFormStatus.Success : SubscribeFormStatus.Error;
|
||||||
|
if (status === SubscribeFormStatus.Success) {
|
||||||
|
analytics.identify(this.state.emailText, 'email');
|
||||||
|
}
|
||||||
this.setState({ status, emailText: '' });
|
this.setState({ status, emailText: '' });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this._setStatus(SubscribeFormStatus.Error);
|
this._setStatus(SubscribeFormStatus.Error);
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
import { generatePseudoRandomSalt, getOrderHashHex } from '@0xproject/order-utils';
|
import { generatePseudoRandomSalt, getOrderHashHex } from '@0xproject/order-utils';
|
||||||
import { colors, constants as sharedConstants } from '@0xproject/react-shared';
|
import { colors } from '@0xproject/react-shared';
|
||||||
import { ECSignature, Order } from '@0xproject/types';
|
import { ECSignature, Order as ZeroExOrder } from '@0xproject/types';
|
||||||
import { BigNumber, logUtils } from '@0xproject/utils';
|
import { BigNumber, logUtils } from '@0xproject/utils';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
import Dialog from 'material-ui/Dialog';
|
import Dialog from 'material-ui/Dialog';
|
||||||
@@ -20,7 +20,7 @@ import { SwapIcon } from 'ts/components/ui/swap_icon';
|
|||||||
import { Dispatcher } from 'ts/redux/dispatcher';
|
import { Dispatcher } from 'ts/redux/dispatcher';
|
||||||
import { portalOrderSchema } from 'ts/schemas/portal_order_schema';
|
import { portalOrderSchema } from 'ts/schemas/portal_order_schema';
|
||||||
import { validator } from 'ts/schemas/validator';
|
import { validator } from 'ts/schemas/validator';
|
||||||
import { AlertTypes, BlockchainErrs, HashData, Side, SideToAssetToken, Token, TokenByAddress } from 'ts/types';
|
import { AlertTypes, BlockchainErrs, HashData, Order, Side, SideToAssetToken, Token, TokenByAddress } from 'ts/types';
|
||||||
import { analytics } from 'ts/utils/analytics';
|
import { analytics } from 'ts/utils/analytics';
|
||||||
import { constants } from 'ts/utils/constants';
|
import { constants } from 'ts/utils/constants';
|
||||||
import { errorReporter } from 'ts/utils/error_reporter';
|
import { errorReporter } from 'ts/utils/error_reporter';
|
||||||
@@ -254,7 +254,8 @@ export class GenerateOrderForm extends React.Component<GenerateOrderFormProps, G
|
|||||||
userAddressIfExists,
|
userAddressIfExists,
|
||||||
debitToken.address,
|
debitToken.address,
|
||||||
);
|
);
|
||||||
const receiveAmount = this.props.sideToAssetToken[Side.Receive].amount;
|
const receiveToken = this.props.sideToAssetToken[Side.Receive];
|
||||||
|
const receiveAmount = receiveToken.amount;
|
||||||
if (
|
if (
|
||||||
!_.isUndefined(debitToken.amount) &&
|
!_.isUndefined(debitToken.amount) &&
|
||||||
!_.isUndefined(receiveAmount) &&
|
!_.isUndefined(receiveAmount) &&
|
||||||
@@ -264,24 +265,28 @@ export class GenerateOrderForm extends React.Component<GenerateOrderFormProps, G
|
|||||||
debitBalance.gte(debitToken.amount) &&
|
debitBalance.gte(debitToken.amount) &&
|
||||||
debitAllowance.gte(debitToken.amount)
|
debitAllowance.gte(debitToken.amount)
|
||||||
) {
|
) {
|
||||||
const didSignSuccessfully = await this._signTransactionAsync();
|
const signedOrder = await this._signTransactionAsync();
|
||||||
if (didSignSuccessfully) {
|
const doesSignedOrderExist = !_.isUndefined(signedOrder);
|
||||||
const networkName = sharedConstants.NETWORK_NAME_BY_ID[this.props.networkId];
|
if (doesSignedOrderExist) {
|
||||||
const eventLabel = `${this.props.tokenByAddress[debitToken.address].symbol}-${networkName}`;
|
analytics.trackOrderEvent('Sign Order Success', signedOrder);
|
||||||
analytics.logEvent('Portal', 'Sign Order Success', eventLabel, debitToken.amount.toNumber());
|
|
||||||
this.setState({
|
this.setState({
|
||||||
globalErrMsg: '',
|
globalErrMsg: '',
|
||||||
shouldShowIncompleteErrs: false,
|
shouldShowIncompleteErrs: false,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return didSignSuccessfully;
|
return doesSignedOrderExist;
|
||||||
} else {
|
} else {
|
||||||
let globalErrMsg = 'You must fix the above errors in order to generate a valid order';
|
let globalErrMsg = 'You must fix the above errors in order to generate a valid order';
|
||||||
if (this.props.userAddress === '') {
|
if (this.props.userAddress === '') {
|
||||||
globalErrMsg = 'You must enable wallet communication';
|
globalErrMsg = 'You must enable wallet communication';
|
||||||
this.props.dispatcher.updateShouldBlockchainErrDialogBeOpen(true);
|
this.props.dispatcher.updateShouldBlockchainErrDialogBeOpen(true);
|
||||||
}
|
}
|
||||||
analytics.logEvent('Portal', 'Sign Order Failure', globalErrMsg);
|
analytics.track('Sign Order Failure', {
|
||||||
|
makerTokenAmount: debitToken.amount.toString(),
|
||||||
|
makerToken: this.props.tokenByAddress[debitToken.address].symbol,
|
||||||
|
takerTokenAmount: receiveToken.amount.toString(),
|
||||||
|
takerToken: this.props.tokenByAddress[receiveToken.address].symbol,
|
||||||
|
});
|
||||||
this.setState({
|
this.setState({
|
||||||
globalErrMsg,
|
globalErrMsg,
|
||||||
shouldShowIncompleteErrs: true,
|
shouldShowIncompleteErrs: true,
|
||||||
@@ -289,7 +294,7 @@ export class GenerateOrderForm extends React.Component<GenerateOrderFormProps, G
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private async _signTransactionAsync(): Promise<boolean> {
|
private async _signTransactionAsync(): Promise<Order | undefined> {
|
||||||
this.setState({
|
this.setState({
|
||||||
signingState: SigningState.SIGNING,
|
signingState: SigningState.SIGNING,
|
||||||
});
|
});
|
||||||
@@ -299,11 +304,11 @@ export class GenerateOrderForm extends React.Component<GenerateOrderFormProps, G
|
|||||||
this.setState({
|
this.setState({
|
||||||
signingState: SigningState.UNSIGNED,
|
signingState: SigningState.UNSIGNED,
|
||||||
});
|
});
|
||||||
return false;
|
return undefined;
|
||||||
}
|
}
|
||||||
const hashData = this.props.hashData;
|
const hashData = this.props.hashData;
|
||||||
|
|
||||||
const zeroExOrder: Order = {
|
const zeroExOrder: ZeroExOrder = {
|
||||||
exchangeContractAddress: exchangeContractAddr,
|
exchangeContractAddress: exchangeContractAddr,
|
||||||
expirationUnixTimestampSec: hashData.orderExpiryTimestamp,
|
expirationUnixTimestampSec: hashData.orderExpiryTimestamp,
|
||||||
feeRecipient: hashData.feeRecipientAddress,
|
feeRecipient: hashData.feeRecipientAddress,
|
||||||
@@ -320,9 +325,10 @@ export class GenerateOrderForm extends React.Component<GenerateOrderFormProps, G
|
|||||||
const orderHash = getOrderHashHex(zeroExOrder);
|
const orderHash = getOrderHashHex(zeroExOrder);
|
||||||
|
|
||||||
let globalErrMsg = '';
|
let globalErrMsg = '';
|
||||||
|
let order;
|
||||||
try {
|
try {
|
||||||
const ecSignature = await this.props.blockchain.signOrderHashAsync(orderHash);
|
const ecSignature = await this.props.blockchain.signOrderHashAsync(orderHash);
|
||||||
const order = utils.generateOrder(
|
order = utils.generateOrder(
|
||||||
exchangeContractAddr,
|
exchangeContractAddr,
|
||||||
this.props.sideToAssetToken,
|
this.props.sideToAssetToken,
|
||||||
hashData.orderExpiryTimestamp,
|
hashData.orderExpiryTimestamp,
|
||||||
@@ -356,7 +362,7 @@ export class GenerateOrderForm extends React.Component<GenerateOrderFormProps, G
|
|||||||
signingState: globalErrMsg === '' ? SigningState.SIGNED : SigningState.UNSIGNED,
|
signingState: globalErrMsg === '' ? SigningState.SIGNED : SigningState.UNSIGNED,
|
||||||
globalErrMsg,
|
globalErrMsg,
|
||||||
});
|
});
|
||||||
return globalErrMsg === '';
|
return order;
|
||||||
}
|
}
|
||||||
private _updateOrderAddress(address?: string): void {
|
private _updateOrderAddress(address?: string): void {
|
||||||
if (!_.isUndefined(address)) {
|
if (!_.isUndefined(address)) {
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
import { constants as sharedConstants, Styles } from '@0xproject/react-shared';
|
import { Styles } from '@0xproject/react-shared';
|
||||||
import { BigNumber, logUtils } from '@0xproject/utils';
|
import { BigNumber, logUtils } from '@0xproject/utils';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
import Toggle from 'material-ui/Toggle';
|
import Toggle from 'material-ui/Toggle';
|
||||||
@@ -111,14 +111,16 @@ export class AllowanceToggle extends React.Component<AllowanceToggleProps, Allow
|
|||||||
if (!this._isAllowanceSet()) {
|
if (!this._isAllowanceSet()) {
|
||||||
newAllowanceAmountInBaseUnits = DEFAULT_ALLOWANCE_AMOUNT_IN_BASE_UNITS;
|
newAllowanceAmountInBaseUnits = DEFAULT_ALLOWANCE_AMOUNT_IN_BASE_UNITS;
|
||||||
}
|
}
|
||||||
const networkName = sharedConstants.NETWORK_NAME_BY_ID[this.props.networkId];
|
const logData = {
|
||||||
const eventLabel = `${this.props.token.symbol}-${networkName}`;
|
tokenSymbol: this.props.token.symbol,
|
||||||
|
newAllowance: newAllowanceAmountInBaseUnits.toNumber(),
|
||||||
|
};
|
||||||
try {
|
try {
|
||||||
await this.props.blockchain.setProxyAllowanceAsync(this.props.token, newAllowanceAmountInBaseUnits);
|
await this.props.blockchain.setProxyAllowanceAsync(this.props.token, newAllowanceAmountInBaseUnits);
|
||||||
analytics.logEvent('Portal', 'Set Allowance Success', eventLabel, newAllowanceAmountInBaseUnits.toNumber());
|
analytics.track('Set Allowances Success', logData);
|
||||||
await this.props.refetchTokenStateAsync();
|
await this.props.refetchTokenStateAsync();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
analytics.logEvent('Portal', 'Set Allowance Failure', eventLabel, newAllowanceAmountInBaseUnits.toNumber());
|
analytics.track('Set Allowance Failure', logData);
|
||||||
this.setState({
|
this.setState({
|
||||||
isSpinnerVisible: false,
|
isSpinnerVisible: false,
|
||||||
});
|
});
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
import { constants as sharedConstants } from '@0xproject/react-shared';
|
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import { RouteComponentProps, withRouter } from 'react-router';
|
import { RouteComponentProps, withRouter } from 'react-router';
|
||||||
@@ -225,20 +224,21 @@ class PlainPortalOnboardingFlow extends React.Component<PortalOnboardingFlowProp
|
|||||||
(this.props.stepIndex === 0 && !this.props.isRunning && this.props.blockchainIsLoaded) ||
|
(this.props.stepIndex === 0 && !this.props.isRunning && this.props.blockchainIsLoaded) ||
|
||||||
(!this.props.isRunning && !this.props.hasBeenClosed && this.props.blockchainIsLoaded)
|
(!this.props.isRunning && !this.props.hasBeenClosed && this.props.blockchainIsLoaded)
|
||||||
) {
|
) {
|
||||||
const networkName = sharedConstants.NETWORK_NAME_BY_ID[this.props.networkId];
|
analytics.track('Onboarding Started', {
|
||||||
analytics.logEvent('Portal', 'Onboarding Started - Automatic', networkName, this.props.stepIndex);
|
reason: 'automatic',
|
||||||
|
stepIndex: this.props.stepIndex,
|
||||||
|
});
|
||||||
this.props.updateIsRunning(true);
|
this.props.updateIsRunning(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private _updateOnboardingStep(stepIndex: number): void {
|
private _updateOnboardingStep(stepIndex: number): void {
|
||||||
const networkName = sharedConstants.NETWORK_NAME_BY_ID[this.props.networkId];
|
|
||||||
this.props.updateOnboardingStep(stepIndex);
|
this.props.updateOnboardingStep(stepIndex);
|
||||||
analytics.logEvent('Portal', 'Update Onboarding Step', networkName, stepIndex);
|
|
||||||
}
|
}
|
||||||
private _closeOnboarding(): void {
|
private _closeOnboarding(): void {
|
||||||
const networkName = sharedConstants.NETWORK_NAME_BY_ID[this.props.networkId];
|
|
||||||
this.props.updateIsRunning(false);
|
this.props.updateIsRunning(false);
|
||||||
analytics.logEvent('Portal', 'Onboarding Closed', networkName, this.props.stepIndex);
|
analytics.track('Onboarding Closed', {
|
||||||
|
stepIndex: this.props.stepIndex,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
private _renderZrxAllowanceToggle(): React.ReactNode {
|
private _renderZrxAllowanceToggle(): React.ReactNode {
|
||||||
const zrxToken = utils.getZrxToken(this.props.tokenByAddress);
|
const zrxToken = utils.getZrxToken(this.props.tokenByAddress);
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
import { ECSignature } from '@0xproject/types';
|
import { ECSignature } from '@0xproject/types';
|
||||||
import { BigNumber, logUtils } from '@0xproject/utils';
|
import { BigNumber, fetchAsync, logUtils } from '@0xproject/utils';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
import Paper from 'material-ui/Paper';
|
import Paper from 'material-ui/Paper';
|
||||||
import TextField from 'material-ui/TextField';
|
import TextField from 'material-ui/TextField';
|
||||||
@@ -148,7 +148,7 @@ You can see and fill it here: ${this.state.shareLink}`);
|
|||||||
const bitlyRequestUrl = `${constants.URL_BITLY_API}/v3/shorten?access_token=${
|
const bitlyRequestUrl = `${constants.URL_BITLY_API}/v3/shorten?access_token=${
|
||||||
configs.BITLY_ACCESS_TOKEN
|
configs.BITLY_ACCESS_TOKEN
|
||||||
}&longUrl=${longUrl}`;
|
}&longUrl=${longUrl}`;
|
||||||
const response = await fetch(bitlyRequestUrl);
|
const response = await fetchAsync(bitlyRequestUrl);
|
||||||
const responseBody = await response.text();
|
const responseBody = await response.text();
|
||||||
const bodyObj = JSON.parse(responseBody);
|
const bodyObj = JSON.parse(responseBody);
|
||||||
if (response.status !== 200 || bodyObj.status_code !== 200) {
|
if (response.status !== 200 || bodyObj.status_code !== 200) {
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
import { colors, constants as sharedConstants } from '@0xproject/react-shared';
|
import { colors } from '@0xproject/react-shared';
|
||||||
import { BigNumber } from '@0xproject/utils';
|
import { BigNumber } from '@0xproject/utils';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
@@ -388,10 +388,11 @@ export class Portal extends React.Component<PortalProps, PortalState> {
|
|||||||
startOnboarding
|
startOnboarding
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private _startOnboarding(): void {
|
private _startOnboarding(): void {
|
||||||
const networkName = sharedConstants.NETWORK_NAME_BY_ID[this.props.networkId];
|
analytics.track('Onboarding Started', {
|
||||||
analytics.logEvent('Portal', 'Onboarding Started - Manual', networkName, this.props.portalOnboardingStep);
|
reason: 'manual',
|
||||||
|
stepIndex: this.props.portalOnboardingStep,
|
||||||
|
});
|
||||||
this.props.dispatcher.updatePortalOnboardingShowing(true);
|
this.props.dispatcher.updatePortalOnboardingShowing(true);
|
||||||
}
|
}
|
||||||
private _renderWalletSection(): React.ReactNode {
|
private _renderWalletSection(): React.ReactNode {
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
import { constants as sharedConstants, Styles } from '@0xproject/react-shared';
|
import { Styles } from '@0xproject/react-shared';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
import { GridTile as PlainGridTile } from 'material-ui/GridList';
|
import { GridTile as PlainGridTile } from 'material-ui/GridList';
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
@@ -64,10 +64,10 @@ export const RelayerGridTile: React.StatelessComponent<RelayerGridTileProps> = (
|
|||||||
const link = props.relayerInfo.appUrl || props.relayerInfo.url;
|
const link = props.relayerInfo.appUrl || props.relayerInfo.url;
|
||||||
const topTokens = props.relayerInfo.topTokens;
|
const topTokens = props.relayerInfo.topTokens;
|
||||||
const weeklyTxnVolume = props.relayerInfo.weeklyTxnVolume;
|
const weeklyTxnVolume = props.relayerInfo.weeklyTxnVolume;
|
||||||
const networkName = sharedConstants.NETWORK_NAME_BY_ID[props.networkId];
|
|
||||||
const eventLabel = `${props.relayerInfo.name}-${networkName}`;
|
|
||||||
const onClick = () => {
|
const onClick = () => {
|
||||||
analytics.logEvent('Portal', 'Relayer Click', eventLabel);
|
analytics.track('Relayer Click', {
|
||||||
|
name: props.relayerInfo.name,
|
||||||
|
});
|
||||||
utils.openUrl(link);
|
utils.openUrl(link);
|
||||||
};
|
};
|
||||||
const headerImageUrl = props.relayerInfo.logoImgUrl;
|
const headerImageUrl = props.relayerInfo.logoImgUrl;
|
||||||
|
@@ -1,9 +1,4 @@
|
|||||||
import {
|
import { colors, EtherscanLinkSuffixes, utils as sharedUtils } from '@0xproject/react-shared';
|
||||||
colors,
|
|
||||||
constants as sharedConstants,
|
|
||||||
EtherscanLinkSuffixes,
|
|
||||||
utils as sharedUtils,
|
|
||||||
} from '@0xproject/react-shared';
|
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
|
|
||||||
@@ -46,11 +41,11 @@ class TokenLink extends React.Component<TokenLinkProps, TokenLinkState> {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
public render(): React.ReactNode {
|
public render(): React.ReactNode {
|
||||||
const networkName = sharedConstants.NETWORK_NAME_BY_ID[this.props.networkId];
|
|
||||||
const eventLabel = `${this.props.tokenInfo.symbol}-${networkName}`;
|
|
||||||
const onClick = (event: React.MouseEvent<HTMLElement>) => {
|
const onClick = (event: React.MouseEvent<HTMLElement>) => {
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
analytics.logEvent('Portal', 'Token Click', eventLabel);
|
analytics.track('Token Click', {
|
||||||
|
tokenSymbol: this.props.tokenInfo.symbol,
|
||||||
|
});
|
||||||
const tokenLink = this._tokenLinkFromToken(this.props.tokenInfo, this.props.networkId);
|
const tokenLink = this._tokenLinkFromToken(this.props.tokenInfo, this.props.networkId);
|
||||||
utils.openUrl(tokenLink);
|
utils.openUrl(tokenLink);
|
||||||
};
|
};
|
||||||
|
@@ -5,7 +5,7 @@ import {
|
|||||||
Styles,
|
Styles,
|
||||||
utils as sharedUtils,
|
utils as sharedUtils,
|
||||||
} from '@0xproject/react-shared';
|
} from '@0xproject/react-shared';
|
||||||
import { BigNumber, errorUtils, logUtils } from '@0xproject/utils';
|
import { BigNumber, errorUtils, fetchAsync, logUtils } from '@0xproject/utils';
|
||||||
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
import Dialog from 'material-ui/Dialog';
|
import Dialog from 'material-ui/Dialog';
|
||||||
@@ -548,7 +548,7 @@ export class TokenBalances extends React.Component<TokenBalancesProps, TokenBala
|
|||||||
await utils.sleepAsync(ARTIFICIAL_FAUCET_REQUEST_DELAY);
|
await utils.sleepAsync(ARTIFICIAL_FAUCET_REQUEST_DELAY);
|
||||||
|
|
||||||
const segment = isEtherRequest ? 'ether' : 'zrx';
|
const segment = isEtherRequest ? 'ether' : 'zrx';
|
||||||
const response = await fetch(
|
const response = await fetchAsync(
|
||||||
`${constants.URL_TESTNET_FAUCET}/${segment}/${this.props.userAddress}?networkId=${this.props.networkId}`,
|
`${constants.URL_TESTNET_FAUCET}/${segment}/${this.props.userAddress}?networkId=${this.props.networkId}`,
|
||||||
);
|
);
|
||||||
const responseBody = await response.text();
|
const responseBody = await response.text();
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
import { constants as sharedConstants, EtherscanLinkSuffixes, utils as sharedUtils } from '@0xproject/react-shared';
|
import { EtherscanLinkSuffixes, utils as sharedUtils } from '@0xproject/react-shared';
|
||||||
import { BigNumber, errorUtils } from '@0xproject/utils';
|
import { BigNumber, errorUtils } from '@0xproject/utils';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
|
|
||||||
@@ -488,19 +488,17 @@ export class Wallet extends React.Component<WalletProps, WalletState> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
private _openWrappedEtherActionRow(wrappedEtherDirection: Side): void {
|
private _openWrappedEtherActionRow(wrappedEtherDirection: Side): void {
|
||||||
const networkName = sharedConstants.NETWORK_NAME_BY_ID[this.props.networkId];
|
|
||||||
const action =
|
const action =
|
||||||
wrappedEtherDirection === Side.Deposit ? 'Wallet - Wrap ETH Opened' : 'Wallet - Unwrap WETH Opened';
|
wrappedEtherDirection === Side.Deposit ? 'Wallet - Wrap ETH Opened' : 'Wallet - Unwrap WETH Opened';
|
||||||
analytics.logEvent('Portal', action, networkName);
|
analytics.track(action);
|
||||||
this.setState({
|
this.setState({
|
||||||
wrappedEtherDirection,
|
wrappedEtherDirection,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
private _closeWrappedEtherActionRow(wrappedEtherDirection: Side): void {
|
private _closeWrappedEtherActionRow(wrappedEtherDirection: Side): void {
|
||||||
const networkName = sharedConstants.NETWORK_NAME_BY_ID[this.props.networkId];
|
|
||||||
const action =
|
const action =
|
||||||
wrappedEtherDirection === Side.Deposit ? 'Wallet - Wrap ETH Closed' : 'Wallet - Unwrap WETH Closed';
|
wrappedEtherDirection === Side.Deposit ? 'Wallet - Wrap ETH Closed' : 'Wallet - Unwrap WETH Closed';
|
||||||
analytics.logEvent('Portal', action, networkName);
|
analytics.track(action);
|
||||||
this.setState({
|
this.setState({
|
||||||
wrappedEtherDirection: undefined,
|
wrappedEtherDirection: undefined,
|
||||||
});
|
});
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
import { constants as sharedConstants, Styles } from '@0xproject/react-shared';
|
import { Styles } from '@0xproject/react-shared';
|
||||||
import { BigNumber, logUtils } from '@0xproject/utils';
|
import { BigNumber, logUtils } from '@0xproject/utils';
|
||||||
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
@@ -188,20 +188,23 @@ export class WrapEtherItem extends React.Component<WrapEtherItemProps, WrapEther
|
|||||||
this.setState({
|
this.setState({
|
||||||
isEthConversionHappening: true,
|
isEthConversionHappening: true,
|
||||||
});
|
});
|
||||||
const networkName = sharedConstants.NETWORK_NAME_BY_ID[this.props.networkId];
|
const etherToken = this.props.etherToken;
|
||||||
|
const amountToConvert = this.state.currentInputAmount;
|
||||||
|
const ethAmount = Web3Wrapper.toUnitAmount(amountToConvert, constants.DECIMAL_PLACES_ETH).toString();
|
||||||
|
const tokenAmount = Web3Wrapper.toUnitAmount(amountToConvert, etherToken.decimals).toString();
|
||||||
try {
|
try {
|
||||||
const etherToken = this.props.etherToken;
|
|
||||||
const amountToConvert = this.state.currentInputAmount;
|
|
||||||
if (this.props.direction === Side.Deposit) {
|
if (this.props.direction === Side.Deposit) {
|
||||||
await this.props.blockchain.convertEthToWrappedEthTokensAsync(etherToken.address, amountToConvert);
|
await this.props.blockchain.convertEthToWrappedEthTokensAsync(etherToken.address, amountToConvert);
|
||||||
const ethAmount = Web3Wrapper.toUnitAmount(amountToConvert, constants.DECIMAL_PLACES_ETH);
|
this.props.dispatcher.showFlashMessage(`Successfully wrapped ${ethAmount} ETH to WETH`);
|
||||||
this.props.dispatcher.showFlashMessage(`Successfully wrapped ${ethAmount.toString()} ETH to WETH`);
|
analytics.track('Wrap ETH Success', {
|
||||||
analytics.logEvent('Portal', 'Wrap ETH Successfully', networkName);
|
amount: ethAmount,
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
await this.props.blockchain.convertWrappedEthTokensToEthAsync(etherToken.address, amountToConvert);
|
await this.props.blockchain.convertWrappedEthTokensToEthAsync(etherToken.address, amountToConvert);
|
||||||
const tokenAmount = Web3Wrapper.toUnitAmount(amountToConvert, etherToken.decimals);
|
this.props.dispatcher.showFlashMessage(`Successfully unwrapped ${tokenAmount} WETH to ETH`);
|
||||||
this.props.dispatcher.showFlashMessage(`Successfully unwrapped ${tokenAmount.toString()} WETH to ETH`);
|
analytics.track('Unwrap WETH Success', {
|
||||||
analytics.logEvent('Portal', 'Unwrap WETH Successfully', networkName);
|
amount: tokenAmount,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
await this.props.refetchEthTokenStateAsync();
|
await this.props.refetchEthTokenStateAsync();
|
||||||
this.props.onConversionSuccessful();
|
this.props.onConversionSuccessful();
|
||||||
@@ -214,10 +217,14 @@ export class WrapEtherItem extends React.Component<WrapEtherItemProps, WrapEther
|
|||||||
logUtils.log(err.stack);
|
logUtils.log(err.stack);
|
||||||
if (this.props.direction === Side.Deposit) {
|
if (this.props.direction === Side.Deposit) {
|
||||||
this.props.dispatcher.showFlashMessage('Failed to wrap your ETH. Please try again.');
|
this.props.dispatcher.showFlashMessage('Failed to wrap your ETH. Please try again.');
|
||||||
analytics.logEvent('Portal', 'Wrap ETH Failed', networkName);
|
analytics.track('Wrap ETH Failure', {
|
||||||
|
amount: ethAmount,
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
this.props.dispatcher.showFlashMessage('Failed to unwrap your WETH. Please try again.');
|
this.props.dispatcher.showFlashMessage('Failed to unwrap your WETH. Please try again.');
|
||||||
analytics.logEvent('Portal', 'Unwrap WETH Failed', networkName);
|
analytics.track('Unwrap WETH Failed', {
|
||||||
|
amount: tokenAmount,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
errorReporter.report(err);
|
errorReporter.report(err);
|
||||||
}
|
}
|
||||||
|
@@ -16,11 +16,9 @@ import { trackedTokenStorage } from 'ts/local_storage/tracked_token_storage';
|
|||||||
import { tradeHistoryStorage } from 'ts/local_storage/trade_history_storage';
|
import { tradeHistoryStorage } from 'ts/local_storage/trade_history_storage';
|
||||||
import { store } from 'ts/redux/store';
|
import { store } from 'ts/redux/store';
|
||||||
import { WebsiteLegacyPaths, WebsitePaths } from 'ts/types';
|
import { WebsiteLegacyPaths, WebsitePaths } from 'ts/types';
|
||||||
import { analytics } from 'ts/utils/analytics';
|
|
||||||
import { muiTheme } from 'ts/utils/mui_theme';
|
import { muiTheme } from 'ts/utils/mui_theme';
|
||||||
import { utils } from 'ts/utils/utils';
|
import { utils } from 'ts/utils/utils';
|
||||||
// Polyfills
|
// Polyfills
|
||||||
import 'whatwg-fetch';
|
|
||||||
injectTapEventPlugin();
|
injectTapEventPlugin();
|
||||||
|
|
||||||
// Check if we've introduced an update that requires us to clear the tradeHistory local storage entries
|
// Check if we've introduced an update that requires us to clear the tradeHistory local storage entries
|
||||||
@@ -69,10 +67,6 @@ const LazyEthereumTypesDocumentation = createLazyComponent('Documentation', asyn
|
|||||||
System.import<any>(/* webpackChunkName: "ethereumTypesDocs" */ 'ts/containers/ethereum_types_documentation'),
|
System.import<any>(/* webpackChunkName: "ethereumTypesDocs" */ 'ts/containers/ethereum_types_documentation'),
|
||||||
);
|
);
|
||||||
|
|
||||||
analytics.init();
|
|
||||||
// tslint:disable-next-line:no-floating-promises
|
|
||||||
analytics.logProviderAsync((window as any).web3);
|
|
||||||
|
|
||||||
render(
|
render(
|
||||||
<Router>
|
<Router>
|
||||||
<div>
|
<div>
|
||||||
|
@@ -205,7 +205,7 @@ export class Wiki extends React.Component<WikiProps, WikiState> {
|
|||||||
articlesBySection,
|
articlesBySection,
|
||||||
},
|
},
|
||||||
async () => {
|
async () => {
|
||||||
await utils.onPageLoadAsync();
|
await utils.onPageLoadPromise;
|
||||||
const hash = this.props.location.hash.slice(1);
|
const hash = this.props.location.hash.slice(1);
|
||||||
sharedUtils.scrollToHash(hash, sharedConstants.SCROLL_CONTAINER_ID);
|
sharedUtils.scrollToHash(hash, sharedConstants.SCROLL_CONTAINER_ID);
|
||||||
},
|
},
|
||||||
|
41
packages/website/ts/redux/analyticsMiddleware.ts
Normal file
41
packages/website/ts/redux/analyticsMiddleware.ts
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
import { Middleware } from 'redux';
|
||||||
|
import { State } from 'ts/redux/reducer';
|
||||||
|
import { ActionTypes } from 'ts/types';
|
||||||
|
import { analytics } from 'ts/utils/analytics';
|
||||||
|
|
||||||
|
export const analyticsMiddleware: Middleware = store => next => action => {
|
||||||
|
const nextAction = next(action);
|
||||||
|
const nextState = (store.getState() as any) as State;
|
||||||
|
switch (action.type) {
|
||||||
|
case ActionTypes.UpdateInjectedProviderName:
|
||||||
|
analytics.addEventProperties({
|
||||||
|
injectedProviderName: nextState.injectedProviderName,
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
case ActionTypes.UpdateNetworkId:
|
||||||
|
analytics.addEventProperties({
|
||||||
|
networkId: nextState.networkId,
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
case ActionTypes.UpdateUserAddress:
|
||||||
|
analytics.addUserProperties({
|
||||||
|
ethAddress: nextState.userAddress,
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
case ActionTypes.UpdateUserEtherBalance:
|
||||||
|
if (nextState.userEtherBalanceInWei) {
|
||||||
|
analytics.addUserProperties({
|
||||||
|
ethBalance: nextState.userEtherBalanceInWei.toString(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ActionTypes.UpdatePortalOnboardingStep:
|
||||||
|
analytics.track('Update Onboarding Step', {
|
||||||
|
stepIndex: nextState.portalOnboardingStep,
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return nextAction;
|
||||||
|
};
|
@@ -1,7 +1,8 @@
|
|||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
import { createStore, Store as ReduxStore } from 'redux';
|
import { applyMiddleware, createStore, Store as ReduxStore } from 'redux';
|
||||||
import { devToolsEnhancer } from 'redux-devtools-extension/developmentOnly';
|
import { composeWithDevTools } from 'redux-devtools-extension/developmentOnly';
|
||||||
import { stateStorage } from 'ts/local_storage/state_storage';
|
import { stateStorage } from 'ts/local_storage/state_storage';
|
||||||
|
import { analyticsMiddleware } from 'ts/redux/analyticsMiddleware';
|
||||||
import { reducer, State } from 'ts/redux/reducer';
|
import { reducer, State } from 'ts/redux/reducer';
|
||||||
|
|
||||||
const ONE_SECOND = 1000;
|
const ONE_SECOND = 1000;
|
||||||
@@ -9,7 +10,7 @@ const ONE_SECOND = 1000;
|
|||||||
export const store: ReduxStore<State> = createStore(
|
export const store: ReduxStore<State> = createStore(
|
||||||
reducer,
|
reducer,
|
||||||
stateStorage.getPersistedDefaultState(),
|
stateStorage.getPersistedDefaultState(),
|
||||||
devToolsEnhancer({ name: '0x Website Redux Store' }),
|
composeWithDevTools(applyMiddleware(analyticsMiddleware)),
|
||||||
);
|
);
|
||||||
store.subscribe(
|
store.subscribe(
|
||||||
_.throttle(() => {
|
_.throttle(() => {
|
||||||
|
@@ -519,8 +519,10 @@ export interface OutdatedWrappedEtherByNetworkId {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ItemByAddress<T> {
|
export type ItemByAddress<T> = ObjectMap<T>;
|
||||||
[address: string]: T;
|
|
||||||
|
export interface ObjectMap<T> {
|
||||||
|
[key: string]: T;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type TokenStateByAddress = ItemByAddress<TokenState>;
|
export type TokenStateByAddress = ItemByAddress<TokenState>;
|
||||||
|
@@ -1,27 +1,83 @@
|
|||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
import * as ReactGA from 'react-ga';
|
import { ObjectMap, Order } from 'ts/types';
|
||||||
import { InjectedWeb3 } from 'ts/types';
|
|
||||||
import { configs } from 'ts/utils/configs';
|
|
||||||
import { utils } from 'ts/utils/utils';
|
import { utils } from 'ts/utils/utils';
|
||||||
|
|
||||||
export const analytics = {
|
export interface HeapAnalytics {
|
||||||
init(): void {
|
loaded: boolean;
|
||||||
ReactGA.initialize(configs.GOOGLE_ANALYTICS_ID);
|
identify(id: string, idType: string): void;
|
||||||
},
|
track(eventName: string, eventProperties?: ObjectMap<string | number>): void;
|
||||||
logEvent(category: string, action: string, label: string, value?: any): void {
|
resetIdentity(): void;
|
||||||
ReactGA.event({
|
addUserProperties(properties: ObjectMap<string | number>): void;
|
||||||
category,
|
addEventProperties(properties: ObjectMap<string | number>): void;
|
||||||
action,
|
removeEventProperty(property: string): void;
|
||||||
label,
|
clearEventProperties(): void;
|
||||||
value,
|
}
|
||||||
});
|
export class Analytics {
|
||||||
},
|
private _heap: HeapAnalytics;
|
||||||
async logProviderAsync(web3IfExists: InjectedWeb3): Promise<void> {
|
public static init(): Analytics {
|
||||||
await utils.onPageLoadAsync();
|
return new Analytics(Analytics.getHeap());
|
||||||
const providerType =
|
}
|
||||||
!_.isUndefined(web3IfExists) && !_.isUndefined(web3IfExists.currentProvider)
|
public static getHeap(): HeapAnalytics {
|
||||||
? utils.getProviderType(web3IfExists.currentProvider)
|
const heap = (window as any).heap;
|
||||||
: 'NONE';
|
if (!_.isUndefined(heap)) {
|
||||||
ReactGA.ga('set', 'dimension1', providerType);
|
return heap;
|
||||||
},
|
} else {
|
||||||
};
|
throw new Error('Could not find the Heap SDK on the page.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
constructor(heap: HeapAnalytics) {
|
||||||
|
this._heap = heap;
|
||||||
|
}
|
||||||
|
// tslint:disable:no-floating-promises
|
||||||
|
// HeapAnalytics Wrappers
|
||||||
|
public identify(id: string, idType: string): void {
|
||||||
|
this._heapLoadedGuardAsync(() => this._heap.identify(id, idType));
|
||||||
|
}
|
||||||
|
public track(eventName: string, eventProperties?: ObjectMap<string | number>): void {
|
||||||
|
this._heapLoadedGuardAsync(() => this._heap.track(eventName, eventProperties));
|
||||||
|
}
|
||||||
|
public resetIdentity(): void {
|
||||||
|
this._heapLoadedGuardAsync(() => this._heap.resetIdentity());
|
||||||
|
}
|
||||||
|
public addUserProperties(properties: ObjectMap<string | number>): void {
|
||||||
|
this._heapLoadedGuardAsync(() => this._heap.addUserProperties(properties));
|
||||||
|
}
|
||||||
|
public addEventProperties(properties: ObjectMap<string | number>): void {
|
||||||
|
this._heapLoadedGuardAsync(() => this._heap.addEventProperties(properties));
|
||||||
|
}
|
||||||
|
public removeEventProperty(property: string): void {
|
||||||
|
this._heapLoadedGuardAsync(() => this._heap.removeEventProperty(property));
|
||||||
|
}
|
||||||
|
public clearEventProperties(): void {
|
||||||
|
this._heapLoadedGuardAsync(() => this._heap.clearEventProperties());
|
||||||
|
}
|
||||||
|
// tslint:enable:no-floating-promises
|
||||||
|
// Custom methods
|
||||||
|
public trackOrderEvent(eventName: string, order: Order): void {
|
||||||
|
const orderLoggingData = {
|
||||||
|
takerTokenAmount: order.signedOrder.takerTokenAmount,
|
||||||
|
makeTokenAmount: order.signedOrder.makerTokenAmount,
|
||||||
|
takerToken: order.metadata.takerToken.symbol,
|
||||||
|
makerToken: order.metadata.makerToken.symbol,
|
||||||
|
};
|
||||||
|
this.track(eventName, orderLoggingData);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Heap is not available as a UMD module, and additionally has the strange property of replacing itself with
|
||||||
|
* a different object once it's loaded.
|
||||||
|
* Instead of having an await call before every analytics use, we opt to have the awaiting logic in here by
|
||||||
|
* guarding every API call with the guard below.
|
||||||
|
*/
|
||||||
|
private async _heapLoadedGuardAsync(callback: () => void): Promise<void> {
|
||||||
|
if (this._heap.loaded) {
|
||||||
|
callback();
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
await utils.onPageLoadPromise;
|
||||||
|
// HACK: Reset heap to loaded heap
|
||||||
|
this._heap = (window as any).heap;
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const analytics = Analytics.init();
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
import { DoxityDocObj, TypeDocNode } from '@0xproject/react-docs';
|
import { DoxityDocObj, TypeDocNode } from '@0xproject/react-docs';
|
||||||
import { logUtils } from '@0xproject/utils';
|
import { fetchAsync, logUtils } from '@0xproject/utils';
|
||||||
import findVersions = require('find-versions');
|
import findVersions = require('find-versions');
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
import { S3FileObject, VersionToFilePath } from 'ts/types';
|
import { S3FileObject, VersionToFilePath } from 'ts/types';
|
||||||
@@ -16,7 +16,7 @@ export const docUtils = {
|
|||||||
return versionToFilePath;
|
return versionToFilePath;
|
||||||
},
|
},
|
||||||
async getVersionFileNamesAsync(s3DocJsonRoot: string, folderName: string): Promise<string[]> {
|
async getVersionFileNamesAsync(s3DocJsonRoot: string, folderName: string): Promise<string[]> {
|
||||||
const response = await fetch(s3DocJsonRoot);
|
const response = await fetchAsync(s3DocJsonRoot);
|
||||||
if (response.status !== 200) {
|
if (response.status !== 200) {
|
||||||
// TODO: Show the user an error message when the docs fail to load
|
// TODO: Show the user an error message when the docs fail to load
|
||||||
const errMsg = await response.text();
|
const errMsg = await response.text();
|
||||||
@@ -73,7 +73,7 @@ export const docUtils = {
|
|||||||
},
|
},
|
||||||
async getJSONDocFileAsync(filePath: string, s3DocJsonRoot: string): Promise<TypeDocNode | DoxityDocObj> {
|
async getJSONDocFileAsync(filePath: string, s3DocJsonRoot: string): Promise<TypeDocNode | DoxityDocObj> {
|
||||||
const endpoint = `${s3DocJsonRoot}/${filePath}`;
|
const endpoint = `${s3DocJsonRoot}/${filePath}`;
|
||||||
const response = await fetch(endpoint);
|
const response = await fetchAsync(endpoint);
|
||||||
if (response.status !== 200) {
|
if (response.status !== 200) {
|
||||||
// TODO: Show the user an error message when the docs fail to load
|
// TODO: Show the user an error message when the docs fail to load
|
||||||
const errMsg = await response.text();
|
const errMsg = await response.text();
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
import { logUtils } from '@0xproject/utils';
|
import { fetchAsync, logUtils } from '@0xproject/utils';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
import * as queryString from 'query-string';
|
import * as queryString from 'query-string';
|
||||||
|
|
||||||
@@ -18,14 +18,14 @@ export const fetchUtils = {
|
|||||||
async requestAsync(baseUrl: string, path: string, queryParams?: object): Promise<any> {
|
async requestAsync(baseUrl: string, path: string, queryParams?: object): Promise<any> {
|
||||||
const query = queryStringFromQueryParams(queryParams);
|
const query = queryStringFromQueryParams(queryParams);
|
||||||
const url = `${baseUrl}${path}${query}`;
|
const url = `${baseUrl}${path}${query}`;
|
||||||
const response = await fetch(url);
|
const response = await fetchAsync(url);
|
||||||
logErrorIfPresent(response, url);
|
logErrorIfPresent(response, url);
|
||||||
const result = await response.json();
|
const result = await response.json();
|
||||||
return result;
|
return result;
|
||||||
},
|
},
|
||||||
async postAsync(baseUrl: string, path: string, body: object): Promise<Response> {
|
async postAsync(baseUrl: string, path: string, body: object): Promise<Response> {
|
||||||
const url = `${baseUrl}${path}`;
|
const url = `${baseUrl}${path}`;
|
||||||
const response = await fetch(url, {
|
const response = await fetchAsync(url, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
|
@@ -299,14 +299,13 @@ export const utils = {
|
|||||||
const baseUrl = `https://${window.location.hostname}${hasPort ? `:${port}` : ''}`;
|
const baseUrl = `https://${window.location.hostname}${hasPort ? `:${port}` : ''}`;
|
||||||
return baseUrl;
|
return baseUrl;
|
||||||
},
|
},
|
||||||
async onPageLoadAsync(): Promise<void> {
|
onPageLoadPromise: new Promise((resolve, _reject) => {
|
||||||
if (document.readyState === 'complete') {
|
if (document.readyState === 'complete') {
|
||||||
return; // Already loaded
|
resolve();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
return new Promise<void>((resolve, _reject) => {
|
window.onload = resolve;
|
||||||
window.onload = () => resolve();
|
}),
|
||||||
});
|
|
||||||
},
|
|
||||||
getProviderType(provider: Provider): Providers | string {
|
getProviderType(provider: Provider): Providers | string {
|
||||||
const constructorName = provider.constructor.name;
|
const constructorName = provider.constructor.name;
|
||||||
let parsedProviderName = constructorName;
|
let parsedProviderName = constructorName;
|
||||||
|
59
yarn.lock
59
yarn.lock
@@ -2,6 +2,23 @@
|
|||||||
# yarn lockfile v1
|
# yarn lockfile v1
|
||||||
|
|
||||||
|
|
||||||
|
"0x.js@0.38.4":
|
||||||
|
version "0.38.4"
|
||||||
|
resolved "https://registry.yarnpkg.com/0x.js/-/0x.js-0.38.4.tgz#735c12d3b8d68945caab87990e6cdd24bf5bc070"
|
||||||
|
dependencies:
|
||||||
|
"@0xproject/assert" "^0.2.12"
|
||||||
|
"@0xproject/base-contract" "^0.3.4"
|
||||||
|
"@0xproject/contract-wrappers" "^0.0.5"
|
||||||
|
"@0xproject/order-utils" "^0.0.7"
|
||||||
|
"@0xproject/order-watcher" "^0.0.6"
|
||||||
|
"@0xproject/sol-compiler" "^0.5.2"
|
||||||
|
"@0xproject/types" "^0.8.1"
|
||||||
|
"@0xproject/typescript-typings" "^0.4.1"
|
||||||
|
"@0xproject/utils" "^0.7.1"
|
||||||
|
"@0xproject/web3-wrapper" "^0.7.1"
|
||||||
|
ethers "3.0.22"
|
||||||
|
lodash "4.17.10"
|
||||||
|
|
||||||
"8fold-marked@0.3.9":
|
"8fold-marked@0.3.9":
|
||||||
version "0.3.9"
|
version "0.3.9"
|
||||||
resolved "https://registry.yarnpkg.com/8fold-marked/-/8fold-marked-0.3.9.tgz#bb89c645612f8ccfaffac1ca6e3c11f168c9cf59"
|
resolved "https://registry.yarnpkg.com/8fold-marked/-/8fold-marked-0.3.9.tgz#bb89c645612f8ccfaffac1ca6e3c11f168c9cf59"
|
||||||
@@ -122,6 +139,24 @@
|
|||||||
ethereumjs-util "5.1.5"
|
ethereumjs-util "5.1.5"
|
||||||
lodash "4.17.10"
|
lodash "4.17.10"
|
||||||
|
|
||||||
|
"@0xproject/order-watcher@^0.0.6":
|
||||||
|
version "0.0.6"
|
||||||
|
resolved "https://registry.yarnpkg.com/@0xproject/order-watcher/-/order-watcher-0.0.6.tgz#85a8fb21e5755bb555f427b12d64d10b89b332e6"
|
||||||
|
dependencies:
|
||||||
|
"@0xproject/assert" "^0.2.12"
|
||||||
|
"@0xproject/base-contract" "^0.3.4"
|
||||||
|
"@0xproject/contract-wrappers" "^0.0.5"
|
||||||
|
"@0xproject/fill-scenarios" "^0.0.4"
|
||||||
|
"@0xproject/json-schemas" "^0.8.1"
|
||||||
|
"@0xproject/order-utils" "^0.0.7"
|
||||||
|
"@0xproject/types" "^0.8.1"
|
||||||
|
"@0xproject/typescript-typings" "^0.4.1"
|
||||||
|
"@0xproject/utils" "^0.7.1"
|
||||||
|
"@0xproject/web3-wrapper" "^0.7.1"
|
||||||
|
bintrees "1.0.2"
|
||||||
|
ethers "3.0.22"
|
||||||
|
lodash "4.17.10"
|
||||||
|
|
||||||
"@0xproject/types@^0.5.0":
|
"@0xproject/types@^0.5.0":
|
||||||
version "0.5.0"
|
version "0.5.0"
|
||||||
resolved "https://registry.yarnpkg.com/@0xproject/types/-/types-0.5.0.tgz#ba3cfbc11a8c6344b57c9680aa7df2ea84b9bf05"
|
resolved "https://registry.yarnpkg.com/@0xproject/types/-/types-0.5.0.tgz#ba3cfbc11a8c6344b57c9680aa7df2ea84b9bf05"
|
||||||
@@ -1834,7 +1869,7 @@ bindings@^1.2.1, bindings@^1.3.0:
|
|||||||
version "1.3.0"
|
version "1.3.0"
|
||||||
resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.3.0.tgz#b346f6ecf6a95f5a815c5839fc7cdb22502f1ed7"
|
resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.3.0.tgz#b346f6ecf6a95f5a815c5839fc7cdb22502f1ed7"
|
||||||
|
|
||||||
bintrees@^1.0.2:
|
bintrees@1.0.2, bintrees@^1.0.2:
|
||||||
version "1.0.2"
|
version "1.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/bintrees/-/bintrees-1.0.2.tgz#49f896d6e858a4a499df85c38fb399b9aff840f8"
|
resolved "https://registry.yarnpkg.com/bintrees/-/bintrees-1.0.2.tgz#49f896d6e858a4a499df85c38fb399b9aff840f8"
|
||||||
|
|
||||||
@@ -3696,7 +3731,7 @@ detect-libc@^1.0.2, detect-libc@^1.0.3:
|
|||||||
version "1.0.3"
|
version "1.0.3"
|
||||||
resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b"
|
resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b"
|
||||||
|
|
||||||
detect-node@^2.0.3:
|
detect-node@2.0.3, detect-node@^2.0.3:
|
||||||
version "2.0.3"
|
version "2.0.3"
|
||||||
resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.0.3.tgz#a2033c09cc8e158d37748fbde7507832bd6ce127"
|
resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.0.3.tgz#a2033c09cc8e158d37748fbde7507832bd6ce127"
|
||||||
|
|
||||||
@@ -6899,7 +6934,7 @@ json-rpc-engine@^3.4.0, json-rpc-engine@^3.6.0:
|
|||||||
json-rpc-error "^2.0.0"
|
json-rpc-error "^2.0.0"
|
||||||
promise-to-callback "^1.0.0"
|
promise-to-callback "^1.0.0"
|
||||||
|
|
||||||
json-rpc-error@^2.0.0:
|
json-rpc-error@2.0.0, json-rpc-error@^2.0.0:
|
||||||
version "2.0.0"
|
version "2.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/json-rpc-error/-/json-rpc-error-2.0.0.tgz#a7af9c202838b5e905c7250e547f1aff77258a02"
|
resolved "https://registry.yarnpkg.com/json-rpc-error/-/json-rpc-error-2.0.0.tgz#a7af9c202838b5e905c7250e547f1aff77258a02"
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -9891,13 +9926,6 @@ react-event-listener@^0.4.5:
|
|||||||
prop-types "^15.5.4"
|
prop-types "^15.5.4"
|
||||||
warning "^3.0.0"
|
warning "^3.0.0"
|
||||||
|
|
||||||
react-ga@^2.4.1:
|
|
||||||
version "2.4.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/react-ga/-/react-ga-2.4.1.tgz#dfbd5f028ed39a07067f7a8bf57dc0d240000767"
|
|
||||||
optionalDependencies:
|
|
||||||
prop-types "^15.6.0"
|
|
||||||
react "^15.6.2 || ^16.0"
|
|
||||||
|
|
||||||
react-highlight@0xproject/react-highlight:
|
react-highlight@0xproject/react-highlight:
|
||||||
version "0.10.0"
|
version "0.10.0"
|
||||||
resolved "https://codeload.github.com/0xproject/react-highlight/tar.gz/83bbb4a09801abd341e2b9041cd884885a4a2098"
|
resolved "https://codeload.github.com/0xproject/react-highlight/tar.gz/83bbb4a09801abd341e2b9041cd884885a4a2098"
|
||||||
@@ -10023,15 +10051,6 @@ react@^15.5.4:
|
|||||||
object-assign "^4.1.0"
|
object-assign "^4.1.0"
|
||||||
prop-types "^15.5.10"
|
prop-types "^15.5.10"
|
||||||
|
|
||||||
"react@^15.6.2 || ^16.0":
|
|
||||||
version "16.3.2"
|
|
||||||
resolved "https://registry.yarnpkg.com/react/-/react-16.3.2.tgz#fdc8420398533a1e58872f59091b272ce2f91ea9"
|
|
||||||
dependencies:
|
|
||||||
fbjs "^0.8.16"
|
|
||||||
loose-envify "^1.1.0"
|
|
||||||
object-assign "^4.1.1"
|
|
||||||
prop-types "^15.6.0"
|
|
||||||
|
|
||||||
read-chunk@^2.1.0:
|
read-chunk@^2.1.0:
|
||||||
version "2.1.0"
|
version "2.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/read-chunk/-/read-chunk-2.1.0.tgz#6a04c0928005ed9d42e1a6ac5600e19cbc7ff655"
|
resolved "https://registry.yarnpkg.com/read-chunk/-/read-chunk-2.1.0.tgz#6a04c0928005ed9d42e1a6ac5600e19cbc7ff655"
|
||||||
@@ -13270,7 +13289,7 @@ websocket@^1.0.24, websocket@^1.0.25:
|
|||||||
typedarray-to-buffer "^3.1.2"
|
typedarray-to-buffer "^3.1.2"
|
||||||
yaeti "^0.0.6"
|
yaeti "^0.0.6"
|
||||||
|
|
||||||
whatwg-fetch@2.0.3, whatwg-fetch@>=0.10.0, whatwg-fetch@^2.0.3:
|
whatwg-fetch@2.0.3, whatwg-fetch@>=0.10.0:
|
||||||
version "2.0.3"
|
version "2.0.3"
|
||||||
resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-2.0.3.tgz#9c84ec2dcf68187ff00bc64e1274b442176e1c84"
|
resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-2.0.3.tgz#9c84ec2dcf68187ff00bc64e1274b442176e1c84"
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user