diff options
44 files changed, 275 insertions, 132 deletions
diff --git a/packages/0x.js/package.json b/packages/0x.js/package.json index d77f31a69..966770cf0 100644 --- a/packages/0x.js/package.json +++ b/packages/0x.js/package.json @@ -105,6 +105,7 @@ "@0xproject/contract-wrappers": "^0.1.0", "@0xproject/order-utils": "^1.0.0", "@0xproject/sol-compiler": "^0.5.3", + "@0xproject/subproviders": "^0.10.5", "@0xproject/types": "^1.0.0", "@0xproject/typescript-typings": "^0.4.2", "@0xproject/utils": "^0.7.2", diff --git a/packages/0x.js/src/index.ts b/packages/0x.js/src/index.ts index 6dfc0bacc..95faa860d 100644 --- a/packages/0x.js/src/index.ts +++ b/packages/0x.js/src/index.ts @@ -1,6 +1,7 @@ export { ZeroEx } from './0x'; export { MessagePrefixType, MessagePrefixOpts } from '@0xproject/order-utils'; +export { Web3ProviderEngine, RPCSubprovider } from '@0xproject/subproviders'; export { ExchangeContractErrs, diff --git a/packages/abi-gen/test/utils_test.ts b/packages/abi-gen/test/utils_test.ts index c6147df38..f3dd38035 100644 --- a/packages/abi-gen/test/utils_test.ts +++ b/packages/abi-gen/test/utils_test.ts @@ -13,8 +13,6 @@ chai.use(dirtyChai); const expect = chai.expect; -const SLEEP_MS = 10; // time to wait before re-timestamping a file - describe('makeOutputFileName()', () => { it('should handle Metacoin usage', () => { expect(utils.makeOutputFileName('Metacoin')).to.equal('metacoin'); @@ -65,19 +63,22 @@ describe('isOutputFileUpToDate()', () => { describe('with an existing output file', () => { let outputFile: string; before(() => { - sleep.msleep(SLEEP_MS); // to ensure different timestamp outputFile = tmp.fileSync( { discardDescriptor: true }, // close file (set timestamp) ).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(); }); it('should return false when output file exists but is older than abi file', () => { - sleep.msleep(SLEEP_MS); // to ensure different timestamp - fs.closeSync(fs.openSync(abiFile, 'w')); // touch abi file + const outFileModTimeMs = fs.statSync(outputFile).mtimeMs; + const abiFileModTimeMs = outFileModTimeMs + 1; + fs.utimesSync(abiFile, abiFileModTimeMs, abiFileModTimeMs); expect(utils.isOutputFileUpToDate(abiFile, outputFile)).to.be.false(); }); diff --git a/packages/connect/package.json b/packages/connect/package.json index cc68d34f4..343df4031 100644 --- a/packages/connect/package.json +++ b/packages/connect/package.json @@ -56,7 +56,6 @@ "@0xproject/types": "^0.8.2", "@0xproject/typescript-typings": "^0.4.2", "@0xproject/utils": "^0.7.2", - "isomorphic-fetch": "^2.2.1", "lodash": "^4.17.4", "query-string": "^5.0.1", "sinon": "^4.0.0", diff --git a/packages/connect/src/http_client.ts b/packages/connect/src/http_client.ts index f6503835a..f3800d581 100644 --- a/packages/connect/src/http_client.ts +++ b/packages/connect/src/http_client.ts @@ -1,7 +1,7 @@ import { assert } from '@0xproject/assert'; import { schemas } from '@0xproject/json-schemas'; import { SignedOrder } from '@0xproject/types'; -import 'isomorphic-fetch'; +import { fetchAsync } from '@0xproject/utils'; import * as _ from 'lodash'; import * as queryString from 'query-string'; @@ -167,7 +167,7 @@ export class HttpClient implements Client { const headers = new Headers({ 'content-type': 'application/json', }); - const response = await fetch(url, { + const response = await fetchAsync(url, { method: requestType, body: JSON.stringify(payload), headers, diff --git a/packages/contract-wrappers/package.json b/packages/contract-wrappers/package.json index b8fd8bd50..a781496ab 100644 --- a/packages/contract-wrappers/package.json +++ b/packages/contract-wrappers/package.json @@ -70,8 +70,7 @@ "sinon": "^4.0.0", "source-map-support": "^0.5.0", "tslint": "5.8.0", - "typescript": "2.7.1", - "web3-provider-engine": "14.0.6" + "typescript": "2.7.1" }, "dependencies": { "@0xproject/assert": "^0.3.0", diff --git a/packages/contract-wrappers/test/erc20_wrapper_test.ts b/packages/contract-wrappers/test/erc20_wrapper_test.ts index 0011508e0..cf7ac527e 100644 --- a/packages/contract-wrappers/test/erc20_wrapper_test.ts +++ b/packages/contract-wrappers/test/erc20_wrapper_test.ts @@ -1,11 +1,10 @@ import { BlockchainLifecycle, callbackErrorReporter } from '@0xproject/dev-utils'; -import { EmptyWalletSubprovider } from '@0xproject/subproviders'; +import { EmptyWalletSubprovider, Web3ProviderEngine } from '@0xproject/subproviders'; import { DoneCallback } from '@0xproject/types'; import { BigNumber } from '@0xproject/utils'; import * as chai from 'chai'; import { Provider } from 'ethereum-types'; import 'mocha'; -import Web3ProviderEngine = require('web3-provider-engine'); import { BlockParamLiteral, diff --git a/packages/contract-wrappers/test/erc721_wrapper_test.ts b/packages/contract-wrappers/test/erc721_wrapper_test.ts index 96b8fcf1d..f005ac2e0 100644 --- a/packages/contract-wrappers/test/erc721_wrapper_test.ts +++ b/packages/contract-wrappers/test/erc721_wrapper_test.ts @@ -1,11 +1,10 @@ import { BlockchainLifecycle, callbackErrorReporter } from '@0xproject/dev-utils'; -import { EmptyWalletSubprovider } from '@0xproject/subproviders'; +import { EmptyWalletSubprovider, Web3ProviderEngine } from '@0xproject/subproviders'; import { DoneCallback } from '@0xproject/types'; import { BigNumber } from '@0xproject/utils'; import * as chai from 'chai'; import { Provider } from 'ethereum-types'; import 'mocha'; -import Web3ProviderEngine = require('web3-provider-engine'); import { BlockParamLiteral, diff --git a/packages/dev-utils/package.json b/packages/dev-utils/package.json index 1808e23e4..f0ef24684 100644 --- a/packages/dev-utils/package.json +++ b/packages/dev-utils/package.json @@ -51,8 +51,7 @@ "ethereum-types": "^0.0.2", "@0xproject/typescript-typings": "^0.4.2", "@0xproject/web3-wrapper": "^0.7.2", - "lodash": "^4.17.4", - "web3-provider-engine": "14.0.6" + "lodash": "^4.17.4" }, "publishConfig": { "access": "public" diff --git a/packages/dev-utils/src/web3_factory.ts b/packages/dev-utils/src/web3_factory.ts index 362a6c3c6..8e713fa68 100644 --- a/packages/dev-utils/src/web3_factory.ts +++ b/packages/dev-utils/src/web3_factory.ts @@ -1,7 +1,10 @@ -import ProviderEngine = require('web3-provider-engine'); -import RpcSubprovider = require('web3-provider-engine/subproviders/rpc'); - -import { EmptyWalletSubprovider, FakeGasEstimateSubprovider, GanacheSubprovider } from '@0xproject/subproviders'; +import { + EmptyWalletSubprovider, + FakeGasEstimateSubprovider, + GanacheSubprovider, + RPCSubprovider, + Web3ProviderEngine, +} from '@0xproject/subproviders'; import * as fs from 'fs'; import * as _ from 'lodash'; @@ -16,8 +19,8 @@ export interface Web3Config { } export const web3Factory = { - getRpcProvider(config: Web3Config = {}): ProviderEngine { - const provider = new ProviderEngine(); + getRpcProvider(config: Web3Config = {}): Web3ProviderEngine { + const provider = new Web3ProviderEngine(); const hasAddresses = _.isUndefined(config.hasAddresses) || config.hasAddresses; config.shouldUseFakeGasEstimate = _.isUndefined(config.shouldUseFakeGasEstimate) || config.shouldUseFakeGasEstimate; @@ -49,11 +52,7 @@ export const web3Factory = { }), ); } else { - provider.addProvider( - new RpcSubprovider({ - rpcUrl: config.rpcUrl || constants.RPC_URL, - }), - ); + provider.addProvider(new RPCSubprovider(config.rpcUrl || constants.RPC_URL)); } provider.start(); return provider; diff --git a/packages/metacoin/package.json b/packages/metacoin/package.json index 9b96441c4..744e9e69a 100644 --- a/packages/metacoin/package.json +++ b/packages/metacoin/package.json @@ -44,8 +44,7 @@ "ethereum-types": "^0.0.2", "ethers": "3.0.22", "lodash": "^4.17.4", - "run-s": "^0.0.0", - "web3-provider-engine": "14.0.6" + "run-s": "^0.0.0" }, "devDependencies": { "@0xproject/dev-utils": "^0.4.5", diff --git a/packages/metacoin/test/utils/web3_wrapper.ts b/packages/metacoin/test/utils/web3_wrapper.ts index d3655cb6a..36bd6343f 100644 --- a/packages/metacoin/test/utils/web3_wrapper.ts +++ b/packages/metacoin/test/utils/web3_wrapper.ts @@ -1,10 +1,8 @@ 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 { Web3Wrapper } from '@0xproject/web3-wrapper'; import * as fs from 'fs'; -import ProviderEngine = require('web3-provider-engine'); -import RpcSubprovider = require('web3-provider-engine/subproviders/rpc'); import { config } from './config'; import { coverage } from './coverage'; @@ -30,7 +28,7 @@ switch (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) { provider.addProvider( new GanacheSubprovider({ @@ -45,7 +43,7 @@ if (testProvider === ProviderType.Ganache) { }), ); } else { - provider.addProvider(new RpcSubprovider({ rpcUrl: 'http://localhost:8501' })); + provider.addProvider(new RPCSubprovider('http://localhost:8501')); } provider.start(); diff --git a/packages/migrations/package.json b/packages/migrations/package.json index 0b7ab8ae2..d4aa73912 100644 --- a/packages/migrations/package.json +++ b/packages/migrations/package.json @@ -60,8 +60,7 @@ "@ledgerhq/hw-app-eth": "^4.3.0", "ethereum-types": "^0.0.2", "ethers": "3.0.22", - "lodash": "^4.17.4", - "web3-provider-engine": "14.0.6" + "lodash": "^4.17.4" }, "optionalDependencies": { "@ledgerhq/hw-transport-node-hid": "^4.3.0" diff --git a/packages/migrations/src/utils/provider_factory.ts b/packages/migrations/src/utils/provider_factory.ts index 7a217b1e0..5f69b258d 100644 --- a/packages/migrations/src/utils/provider_factory.ts +++ b/packages/migrations/src/utils/provider_factory.ts @@ -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'; // tslint:disable:no-implicit-dependencies import TransportNodeHid from '@ledgerhq/hw-transport-node-hid'; import { Provider } from 'ethereum-types'; -import ProviderEngine = require('web3-provider-engine'); -import RpcSubprovider = require('web3-provider-engine/subproviders/rpc'); import { constants } from './constants'; @@ -15,18 +13,14 @@ async function ledgerEthereumNodeJsClientFactoryAsync(): Promise<LedgerEthereumC } export const providerFactory = { async getLedgerProviderAsync(): Promise<Provider> { - const provider = new ProviderEngine(); + const provider = new Web3ProviderEngine(); const ledgerWalletConfigs = { networkId: constants.KOVAN_NETWORK_ID, ledgerEthereumClientFactoryAsync: ledgerEthereumNodeJsClientFactoryAsync, }; const ledgerSubprovider = new LedgerSubprovider(ledgerWalletConfigs); provider.addProvider(ledgerSubprovider); - provider.addProvider( - new RpcSubprovider({ - rpcUrl: constants.RPC_URL, - }), - ); + provider.addProvider(new RPCSubprovider(constants.RPC_URL)); provider.start(); return provider; }, diff --git a/packages/sol-compiler/package.json b/packages/sol-compiler/package.json index e738ab56b..8460420ad 100644 --- a/packages/sol-compiler/package.json +++ b/packages/sol-compiler/package.json @@ -87,7 +87,6 @@ "ethereum-types": "^0.0.2", "chalk": "^2.3.0", "ethereumjs-util": "^5.1.1", - "isomorphic-fetch": "^2.2.1", "lodash": "^4.17.4", "mkdirp": "^0.5.1", "require-from-string": "^2.0.1", diff --git a/packages/sol-compiler/src/compiler.ts b/packages/sol-compiler/src/compiler.ts index bb701a8ce..e61c606be 100644 --- a/packages/sol-compiler/src/compiler.ts +++ b/packages/sol-compiler/src/compiler.ts @@ -8,11 +8,10 @@ import { Resolver, URLResolver, } from '@0xproject/sol-resolver'; -import { logUtils } from '@0xproject/utils'; +import { fetchAsync, logUtils } from '@0xproject/utils'; import chalk from 'chalk'; import * as ethUtil from 'ethereumjs-util'; import * as fs from 'fs'; -import 'isomorphic-fetch'; import * as _ from 'lodash'; import * as path from 'path'; import * as requireFromString from 'require-from-string'; @@ -149,7 +148,7 @@ export class Compiler { } else { logUtils.log(`Downloading ${fullSolcVersion}...`); const url = `${constants.BASE_COMPILER_URL}${fullSolcVersion}`; - const response = await fetch(url); + const response = await fetchAsync(url); const SUCCESS_STATUS = 200; if (response.status !== SUCCESS_STATUS) { throw new Error(`Failed to load ${fullSolcVersion}`); diff --git a/packages/subproviders/package.json b/packages/subproviders/package.json index bdc846e6b..796d87cf4 100644 --- a/packages/subproviders/package.json +++ b/packages/subproviders/package.json @@ -55,6 +55,7 @@ "ethereumjs-util": "^5.1.1", "ganache-core": "0xProject/ganache-core", "hdkey": "^0.7.1", + "json-rpc-error": "2.0.0", "lodash": "^4.17.4", "semaphore-async-await": "^1.5.1", "web3-provider-engine": "14.0.6" diff --git a/packages/subproviders/src/index.ts b/packages/subproviders/src/index.ts index 71d643f14..9d4480e59 100644 --- a/packages/subproviders/src/index.ts +++ b/packages/subproviders/src/index.ts @@ -1,5 +1,6 @@ import Eth from '@ledgerhq/hw-app-eth'; import TransportU2F from '@ledgerhq/hw-transport-u2f'; +export import Web3ProviderEngine = require('web3-provider-engine'); export { ECSignature } from '@0xproject/types'; import { LedgerEthereumClient } from './types'; @@ -10,6 +11,7 @@ export { FakeGasEstimateSubprovider } from './subproviders/fake_gas_estimate_sub export { SignerSubprovider } from './subproviders/signer'; export { RedundantSubprovider } from './subproviders/redundant_subprovider'; export { LedgerSubprovider } from './subproviders/ledger'; +export { RPCSubprovider } from './subproviders/rpc_subprovider'; export { GanacheSubprovider } from './subproviders/ganache'; export { Subprovider } from './subproviders/subprovider'; export { NonceTrackerSubprovider } from './subproviders/nonce_tracker'; diff --git a/packages/subproviders/src/subproviders/rpc_subprovider.ts b/packages/subproviders/src/subproviders/rpc_subprovider.ts new file mode 100644 index 000000000..3ad0e5325 --- /dev/null +++ b/packages/subproviders/src/subproviders/rpc_subprovider.ts @@ -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); + } +} diff --git a/packages/subproviders/src/subproviders/subprovider.ts b/packages/subproviders/src/subproviders/subprovider.ts index ff8378c4e..5dc273569 100644 --- a/packages/subproviders/src/subproviders/subprovider.ts +++ b/packages/subproviders/src/subproviders/subprovider.ts @@ -9,18 +9,7 @@ import { Callback, ErrorCallback, JSONRPCRequestPayloadWithMethod } from '../typ export abstract class Subprovider { // tslint:disable-next-line:underscore-private-and-protected private engine!: Provider; - // 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; - } - private static _createFinalPayload( + protected static _createFinalPayload( payload: Partial<JSONRPCRequestPayloadWithMethod>, ): Partial<JSONRPCRequestPayloadWithMethod> { const finalPayload = { @@ -32,6 +21,17 @@ export abstract class Subprovider { }; 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 public abstract async handleRequest( payload: JSONRPCRequestPayload, diff --git a/packages/subproviders/src/utils/subprovider_utils.ts b/packages/subproviders/src/utils/subprovider_utils.ts index 24ebedd06..beda408ab 100644 --- a/packages/subproviders/src/utils/subprovider_utils.ts +++ b/packages/subproviders/src/utils/subprovider_utils.ts @@ -1,4 +1,4 @@ -import ProviderEngine = require('web3-provider-engine'); +import Web3ProviderEngine = require('web3-provider-engine'); import { Subprovider } from '../subproviders/subprovider'; @@ -7,7 +7,7 @@ import { Subprovider } from '../subproviders/subprovider'; * @param provider Given provider * @param subprovider Subprovider to prepend */ -export function prependSubprovider(provider: ProviderEngine, subprovider: Subprovider): void { +export function prependSubprovider(provider: Web3ProviderEngine, subprovider: Subprovider): void { subprovider.setEngine(provider); // HACK: We use implementation details of provider engine here // https://github.com/MetaMask/provider-engine/blob/master/index.js#L68 diff --git a/packages/subproviders/test/integration/ledger_subprovider_test.ts b/packages/subproviders/test/integration/ledger_subprovider_test.ts index 196cecf32..103e8f952 100644 --- a/packages/subproviders/test/integration/ledger_subprovider_test.ts +++ b/packages/subproviders/test/integration/ledger_subprovider_test.ts @@ -7,10 +7,8 @@ import TransportNodeHid from '@ledgerhq/hw-transport-node-hid'; import * as chai from 'chai'; import { JSONRPCResponsePayload } from 'ethereum-types'; 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 { chaiSetup } from '../chai_setup'; import { fixtureData } from '../utils/fixture_data'; @@ -86,9 +84,7 @@ describe('LedgerSubprovider', () => { before(() => { ledgerProvider = new Web3ProviderEngine(); ledgerProvider.addProvider(ledgerSubprovider); - const httpProvider = new RpcSubprovider({ - rpcUrl: 'http://localhost:8545', - }); + const httpProvider = new RPCSubprovider('http://localhost:8545'); ledgerProvider.addProvider(httpProvider); ledgerProvider.start(); diff --git a/packages/subproviders/test/unit/eth_lightwallet_subprovider_test.ts b/packages/subproviders/test/unit/eth_lightwallet_subprovider_test.ts index f17c21f02..063817a95 100644 --- a/packages/subproviders/test/unit/eth_lightwallet_subprovider_test.ts +++ b/packages/subproviders/test/unit/eth_lightwallet_subprovider_test.ts @@ -2,9 +2,8 @@ import * as chai from 'chai'; import * as lightwallet from 'eth-lightwallet'; import { JSONRPCResponsePayload } from 'ethereum-types'; 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 { chaiSetup } from '../chai_setup'; import { fixtureData } from '../utils/fixture_data'; diff --git a/packages/subproviders/test/unit/ledger_subprovider_test.ts b/packages/subproviders/test/unit/ledger_subprovider_test.ts index 3b57e125b..edff5144e 100644 --- a/packages/subproviders/test/unit/ledger_subprovider_test.ts +++ b/packages/subproviders/test/unit/ledger_subprovider_test.ts @@ -2,9 +2,8 @@ import * as chai from 'chai'; import { JSONRPCResponsePayload } from 'ethereum-types'; import * as ethUtils from 'ethereumjs-util'; import * as _ from 'lodash'; -import Web3ProviderEngine = require('web3-provider-engine'); -import { LedgerSubprovider } from '../../src'; +import { LedgerSubprovider, Web3ProviderEngine } from '../../src'; import { DoneCallback, LedgerCommunicationClient, diff --git a/packages/subproviders/test/unit/mnemonic_wallet_subprovider_test.ts b/packages/subproviders/test/unit/mnemonic_wallet_subprovider_test.ts index 51ba7094c..f2bdda3cd 100644 --- a/packages/subproviders/test/unit/mnemonic_wallet_subprovider_test.ts +++ b/packages/subproviders/test/unit/mnemonic_wallet_subprovider_test.ts @@ -1,9 +1,8 @@ import * as chai from 'chai'; import { JSONRPCResponsePayload } from 'ethereum-types'; 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 { chaiSetup } from '../chai_setup'; import { fixtureData } from '../utils/fixture_data'; diff --git a/packages/subproviders/test/unit/nonce_tracker_subprovider_test.ts b/packages/subproviders/test/unit/nonce_tracker_subprovider_test.ts index fa33cd50a..c437d0815 100644 --- a/packages/subproviders/test/unit/nonce_tracker_subprovider_test.ts +++ b/packages/subproviders/test/unit/nonce_tracker_subprovider_test.ts @@ -1,11 +1,10 @@ import * as chai from 'chai'; -import Web3ProviderEngine = require('web3-provider-engine'); import FixtureSubprovider = require('web3-provider-engine/subproviders/fixture'); import { promisify } from '@0xproject/utils'; import EthereumTx = require('ethereumjs-tx'); -import { NonceTrackerSubprovider } from '../../src'; +import { NonceTrackerSubprovider, Web3ProviderEngine } from '../../src'; import { chaiSetup } from '../chai_setup'; const expect = chai.expect; diff --git a/packages/subproviders/test/unit/private_key_wallet_subprovider_test.ts b/packages/subproviders/test/unit/private_key_wallet_subprovider_test.ts index ab321bcff..95773145f 100644 --- a/packages/subproviders/test/unit/private_key_wallet_subprovider_test.ts +++ b/packages/subproviders/test/unit/private_key_wallet_subprovider_test.ts @@ -1,9 +1,8 @@ import * as chai from 'chai'; import { JSONRPCResponsePayload } from 'ethereum-types'; 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 { chaiSetup } from '../chai_setup'; import { fixtureData } from '../utils/fixture_data'; diff --git a/packages/subproviders/test/unit/redundant_rpc_subprovider_test.ts b/packages/subproviders/test/unit/redundant_rpc_subprovider_test.ts index 810fb8f45..e30d2f74e 100644 --- a/packages/subproviders/test/unit/redundant_rpc_subprovider_test.ts +++ b/packages/subproviders/test/unit/redundant_rpc_subprovider_test.ts @@ -2,10 +2,8 @@ import { DoneCallback } from '@0xproject/types'; import * as chai from 'chai'; import { JSONRPCResponsePayload } from 'ethereum-types'; 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 { chaiSetup } from '../chai_setup'; import { ganacheSubprovider } from '../utils/ganache_subprovider'; @@ -39,9 +37,7 @@ describe('RedundantSubprovider', () => { }); it('succeeds when supplied at least one healthy endpoint', (done: DoneCallback) => { provider = new Web3ProviderEngine(); - const nonExistentSubprovider = new RpcSubprovider({ - rpcUrl: 'http://does-not-exist:3000', - }); + const nonExistentSubprovider = new RPCSubprovider('http://does-not-exist:3000'); const handleRequestStub = Sinon.stub(nonExistentSubprovider, 'handleRequest').throws( new Error('REQUEST_FAILED'), ); diff --git a/packages/testnet-faucets/package.json b/packages/testnet-faucets/package.json index 72ab8f61b..442f488c9 100644 --- a/packages/testnet-faucets/package.json +++ b/packages/testnet-faucets/package.json @@ -18,7 +18,7 @@ "author": "Fabio Berger", "license": "Apache-2.0", "dependencies": { - "0x.js": "^0.38.0", + "0x.js": "0.38.4", "@0xproject/subproviders": "^0.10.5", "@0xproject/web3-wrapper": "^0.7.2", "@0xproject/typescript-typings": "^0.4.2", @@ -28,8 +28,7 @@ "ethereumjs-util": "^5.1.1", "express": "^4.15.2", "lodash": "^4.17.4", - "rollbar": "^0.6.5", - "web3-provider-engine": "14.0.6" + "rollbar": "^0.6.5" }, "devDependencies": { "@0xproject/tslint-config": "^0.4.21", diff --git a/packages/testnet-faucets/src/ts/handler.ts b/packages/testnet-faucets/src/ts/handler.ts index 6d26691d6..0f61159fa 100644 --- a/packages/testnet-faucets/src/ts/handler.ts +++ b/packages/testnet-faucets/src/ts/handler.ts @@ -5,9 +5,12 @@ import { Provider } from 'ethereum-types'; import * as express from 'express'; import * as _ from 'lodash'; -import { NonceTrackerSubprovider, PrivateKeyWalletSubprovider } from '@0xproject/subproviders'; -import ProviderEngine = require('web3-provider-engine'); -import RpcSubprovider = require('web3-provider-engine/subproviders/rpc'); +import { + NonceTrackerSubprovider, + PrivateKeyWalletSubprovider, + RPCSubprovider, + Web3ProviderEngine, +} from '@0xproject/subproviders'; import { configs } from './configs'; import { constants } from './constants'; @@ -39,14 +42,10 @@ export class Handler { if (_.isUndefined(configs.DISPENSER_PRIVATE_KEY)) { throw new Error('Dispenser Private key not found'); } - const engine = new ProviderEngine(); + const engine = new Web3ProviderEngine(); engine.addProvider(new NonceTrackerSubprovider()); engine.addProvider(new PrivateKeyWalletSubprovider(configs.DISPENSER_PRIVATE_KEY)); - engine.addProvider( - new RpcSubprovider({ - rpcUrl, - }), - ); + engine.addProvider(new RPCSubprovider(rpcUrl)); engine.start(); return engine; } diff --git a/packages/types/src/index.ts b/packages/types/src/index.ts index 03fa2fe8a..72e2a726b 100644 --- a/packages/types/src/index.ts +++ b/packages/types/src/index.ts @@ -221,3 +221,11 @@ export enum RevertReason { ValueGreaterThanZero = 'VALUE_GREATER_THAN_ZERO', InvalidMsgValue = 'INVALID_MSG_VALUE', } + +export enum StatusCodes { + Success = 200, + NotFound = 404, + InternalError = 500, + MethodNotAllowed = 405, + GatewayTimeout = 504, +} diff --git a/packages/typescript-typings/types/detect-node/index.d.ts b/packages/typescript-typings/types/detect-node/index.d.ts new file mode 100644 index 000000000..4c58b8450 --- /dev/null +++ b/packages/typescript-typings/types/detect-node/index.d.ts @@ -0,0 +1,3 @@ +declare module 'detect-node' { + export const isNode: boolean; +} diff --git a/packages/typescript-typings/types/json-rpc-error/index.d.ts b/packages/typescript-typings/types/json-rpc-error/index.d.ts new file mode 100644 index 000000000..dfaf92167 --- /dev/null +++ b/packages/typescript-typings/types/json-rpc-error/index.d.ts @@ -0,0 +1,8 @@ +declare module 'json-rpc-error' { + export class InternalError extends Error { + constructor(err: Error | string); + } + export class MethodNotFound extends Error { + constructor(); + } +} diff --git a/packages/utils/package.json b/packages/utils/package.json index 9168a3538..a454b35ee 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -35,14 +35,15 @@ "typescript": "2.7.1" }, "dependencies": { - "ethereum-types": "^0.0.2", + "@0xproject/types": "^1.0.0", "@0xproject/typescript-typings": "^0.4.2", "@types/node": "^8.0.53", - "ethereumjs-util": "^5.1.1", "bignumber.js": "~4.1.0", + "detect-node": "2.0.3", "ethereum-types": "^0.0.2", "ethereumjs-util": "^5.1.1", "ethers": "3.0.22", + "isomorphic-fetch": "^2.2.1", "js-sha3": "^0.7.0", "lodash": "^4.17.4" }, diff --git a/packages/utils/src/fetchAsync.ts b/packages/utils/src/fetchAsync.ts new file mode 100644 index 000000000..47d87815e --- /dev/null +++ b/packages/utils/src/fetchAsync.ts @@ -0,0 +1,32 @@ +import isNode = require('detect-node'); +import 'isomorphic-fetch'; + +export const fetchAsync = async ( + endpoint: string, + options: RequestInit = {}, + timeoutMs: number = 20000, +): Promise<Response> => { + 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; +}; diff --git a/packages/utils/src/index.ts b/packages/utils/src/index.ts index fd102cecb..b8e0b1775 100644 --- a/packages/utils/src/index.ts +++ b/packages/utils/src/index.ts @@ -8,3 +8,4 @@ export { logUtils } from './log_utils'; export { abiUtils } from './abi_utils'; export { NULL_BYTES } from './constants'; export { errorUtils } from './error_utils'; +export { fetchAsync } from './fetchAsync'; diff --git a/packages/website/package.json b/packages/website/package.json index b5b4b6119..2d054693b 100644 --- a/packages/website/package.json +++ b/packages/website/package.json @@ -63,7 +63,6 @@ "thenby": "^1.2.3", "truffle-contract": "2.0.1", "web3-provider-engine": "14.0.6", - "whatwg-fetch": "^2.0.3", "xml-js": "^1.6.4" }, "devDependencies": { diff --git a/packages/website/ts/blockchain.ts b/packages/website/ts/blockchain.ts index 0e6698318..099171c45 100644 --- a/packages/website/ts/blockchain.ts +++ b/packages/website/ts/blockchain.ts @@ -15,8 +15,10 @@ import { ledgerEthereumBrowserClientFactoryAsync, LedgerSubprovider, RedundantSubprovider, + RPCSubprovider, SignerSubprovider, Subprovider, + Web3ProviderEngine, } from '@0xproject/subproviders'; import { BlockParam, @@ -60,9 +62,7 @@ import { configs } from 'ts/utils/configs'; import { constants } from 'ts/utils/constants'; import { errorReporter } from 'ts/utils/error_reporter'; import { utils } from 'ts/utils/utils'; -import ProviderEngine = require('web3-provider-engine'); import FilterSubprovider = require('web3-provider-engine/subproviders/filters'); -import RpcSubprovider = require('web3-provider-engine/subproviders/rpc'); import * as MintableArtifacts from '../contracts/Mintable.json'; @@ -148,7 +148,7 @@ export class Blockchain { if (!isU2FSupported) { throw new Error('Cannot update providerType to LEDGER without U2F support'); } - const provider = new ProviderEngine(); + const provider = new Web3ProviderEngine(); const ledgerWalletConfigs = { networkId: networkIdIfExists, ledgerEthereumClientFactoryAsync: ledgerEthereumBrowserClientFactoryAsync, @@ -157,9 +157,7 @@ export class Blockchain { provider.addProvider(ledgerSubprovider); provider.addProvider(new FilterSubprovider()); const rpcSubproviders = _.map(configs.PUBLIC_NODE_URLS_BY_NETWORK_ID[networkIdIfExists], publicNodeUrl => { - return new RpcSubprovider({ - rpcUrl: publicNodeUrl, - }); + return new RPCSubprovider(publicNodeUrl); }); provider.addProvider(new RedundantSubprovider(rpcSubproviders as Subprovider[])); provider.start(); @@ -167,13 +165,11 @@ export class Blockchain { } else if (doesInjectedWeb3Exist && isPublicNodeAvailableForNetworkId) { // We catch all requests involving a users account and send it to the injectedWeb3 // 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 FilterSubprovider()); const rpcSubproviders = _.map(publicNodeUrlsIfExistsForNetworkId, publicNodeUrl => { - return new RpcSubprovider({ - rpcUrl: publicNodeUrl, - }); + return new RPCSubprovider(publicNodeUrl); }); provider.addProvider(new RedundantSubprovider(rpcSubproviders as Subprovider[])); provider.start(); @@ -185,13 +181,11 @@ export class Blockchain { // 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 // injected into their browser. - const provider = new ProviderEngine(); + const provider = new Web3ProviderEngine(); provider.addProvider(new FilterSubprovider()); const networkId = constants.NETWORK_ID_MAINNET; const rpcSubproviders = _.map(configs.PUBLIC_NODE_URLS_BY_NETWORK_ID[networkId], publicNodeUrl => { - return new RpcSubprovider({ - rpcUrl: publicNodeUrl, - }); + return new RPCSubprovider(publicNodeUrl); }); provider.addProvider(new RedundantSubprovider(rpcSubproviders as Subprovider[])); provider.start(); diff --git a/packages/website/ts/components/order_json.tsx b/packages/website/ts/components/order_json.tsx index 35188c024..7a732de6a 100644 --- a/packages/website/ts/components/order_json.tsx +++ b/packages/website/ts/components/order_json.tsx @@ -1,5 +1,5 @@ import { ECSignature } from '@0xproject/types'; -import { BigNumber, logUtils } from '@0xproject/utils'; +import { BigNumber, fetchAsync, logUtils } from '@0xproject/utils'; import * as _ from 'lodash'; import Paper from 'material-ui/Paper'; 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=${ configs.BITLY_ACCESS_TOKEN }&longUrl=${longUrl}`; - const response = await fetch(bitlyRequestUrl); + const response = await fetchAsync(bitlyRequestUrl); const responseBody = await response.text(); const bodyObj = JSON.parse(responseBody); if (response.status !== 200 || bodyObj.status_code !== 200) { diff --git a/packages/website/ts/components/token_balances.tsx b/packages/website/ts/components/token_balances.tsx index 3fae83c00..1f2dfccb0 100644 --- a/packages/website/ts/components/token_balances.tsx +++ b/packages/website/ts/components/token_balances.tsx @@ -5,7 +5,7 @@ import { Styles, utils as sharedUtils, } 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 * as _ from 'lodash'; 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); 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}`, ); const responseBody = await response.text(); diff --git a/packages/website/ts/index.tsx b/packages/website/ts/index.tsx index 7ceec8c2c..e6b869bf4 100644 --- a/packages/website/ts/index.tsx +++ b/packages/website/ts/index.tsx @@ -20,7 +20,6 @@ import { analytics } from 'ts/utils/analytics'; import { muiTheme } from 'ts/utils/mui_theme'; import { utils } from 'ts/utils/utils'; // Polyfills -import 'whatwg-fetch'; injectTapEventPlugin(); // Check if we've introduced an update that requires us to clear the tradeHistory local storage entries diff --git a/packages/website/ts/utils/doc_utils.ts b/packages/website/ts/utils/doc_utils.ts index 7768835fb..1627b9b0c 100644 --- a/packages/website/ts/utils/doc_utils.ts +++ b/packages/website/ts/utils/doc_utils.ts @@ -1,5 +1,5 @@ import { DoxityDocObj, TypeDocNode } from '@0xproject/react-docs'; -import { logUtils } from '@0xproject/utils'; +import { fetchAsync, logUtils } from '@0xproject/utils'; import findVersions = require('find-versions'); import * as _ from 'lodash'; import { S3FileObject, VersionToFilePath } from 'ts/types'; @@ -16,7 +16,7 @@ export const docUtils = { return versionToFilePath; }, async getVersionFileNamesAsync(s3DocJsonRoot: string, folderName: string): Promise<string[]> { - const response = await fetch(s3DocJsonRoot); + const response = await fetchAsync(s3DocJsonRoot); if (response.status !== 200) { // TODO: Show the user an error message when the docs fail to load const errMsg = await response.text(); @@ -73,7 +73,7 @@ export const docUtils = { }, async getJSONDocFileAsync(filePath: string, s3DocJsonRoot: string): Promise<TypeDocNode | DoxityDocObj> { const endpoint = `${s3DocJsonRoot}/${filePath}`; - const response = await fetch(endpoint); + const response = await fetchAsync(endpoint); if (response.status !== 200) { // TODO: Show the user an error message when the docs fail to load const errMsg = await response.text(); diff --git a/packages/website/ts/utils/fetch_utils.ts b/packages/website/ts/utils/fetch_utils.ts index 513f7e479..f159e3180 100644 --- a/packages/website/ts/utils/fetch_utils.ts +++ b/packages/website/ts/utils/fetch_utils.ts @@ -1,4 +1,4 @@ -import { logUtils } from '@0xproject/utils'; +import { fetchAsync, logUtils } from '@0xproject/utils'; import * as _ from 'lodash'; import * as queryString from 'query-string'; @@ -19,14 +19,14 @@ export const fetchUtils = { async requestAsync(baseUrl: string, path: string, queryParams?: object): Promise<any> { const query = queryStringFromQueryParams(queryParams); const url = `${baseUrl}${path}${query}`; - const response = await fetch(url); + const response = await fetchAsync(url); logErrorIfPresent(response, url); const result = await response.json(); return result; }, async postAsync(baseUrl: string, path: string, body: object): Promise<Response> { const url = `${baseUrl}${path}`; - const response = await fetch(url, { + const response = await fetchAsync(url, { method: 'POST', headers: { 'Content-Type': 'application/json', @@ -2,6 +2,23 @@ # 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": version "0.3.9" resolved "https://registry.yarnpkg.com/8fold-marked/-/8fold-marked-0.3.9.tgz#bb89c645612f8ccfaffac1ca6e3c11f168c9cf59" @@ -122,6 +139,24 @@ ethereumjs-util "5.1.5" 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": version "0.5.0" 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" 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" resolved "https://registry.yarnpkg.com/bintrees/-/bintrees-1.0.2.tgz#49f896d6e858a4a499df85c38fb399b9aff840f8" @@ -4481,9 +4516,9 @@ ethereumjs-wallet@~0.6.0: utf8 "^2.1.1" uuid "^2.0.1" -ethers@3.0.22: - version "3.0.22" - resolved "https://registry.yarnpkg.com/ethers/-/ethers-3.0.22.tgz#7fab1ea16521705837aa43c15831877b2716b436" +ethers@0xproject/ethers.js#eip-838-reasons, ethers@3.0.22: + version "3.0.18" + resolved "https://codeload.github.com/0xproject/ethers.js/tar.gz/b91342bd200d142af0165d6befddf783c8ae8447" dependencies: aes-js "3.0.0" bn.js "^4.4.0" @@ -6899,7 +6934,7 @@ json-rpc-engine@^3.4.0, json-rpc-engine@^3.6.0: json-rpc-error "^2.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" resolved "https://registry.yarnpkg.com/json-rpc-error/-/json-rpc-error-2.0.0.tgz#a7af9c202838b5e905c7250e547f1aff77258a02" dependencies: @@ -13270,7 +13305,7 @@ websocket@^1.0.24, websocket@^1.0.25: typedarray-to-buffer "^3.1.2" 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" resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-2.0.3.tgz#9c84ec2dcf68187ff00bc64e1274b442176e1c84" |