diff --git a/packages/abi-gen-templates/contract.handlebars b/packages/abi-gen-templates/contract.handlebars index 7e7171c702..c2dc6a4084 100644 --- a/packages/abi-gen-templates/contract.handlebars +++ b/packages/abi-gen-templates/contract.handlebars @@ -2,8 +2,8 @@ // tslint:disable:no-unused-variable // tslint:disable:no-unbound-method import { BaseContract } from '@0x/base-contract'; -import { BlockParam, BlockParamLiteral, CallData, ContractAbi, ContractArtifact, DecodedLogArgs, MethodAbi, Provider, TxData, TxDataPayable } from 'ethereum-types'; -import { BigNumber, classUtils, logUtils } from '@0x/utils'; +import { BlockParam, BlockParamLiteral, CallData, ContractAbi, ContractArtifact, DecodedLogArgs, MethodAbi, TxData, TxDataPayable, SupportedProvider } from 'ethereum-types'; +import { BigNumber, classUtils, logUtils, providerUtils } from '@0x/utils'; import { SimpleContractArtifact } from '@0x/types'; import { Web3Wrapper } from '@0x/web3-wrapper'; import * as ethers from 'ethers'; @@ -42,13 +42,14 @@ export class {{contractName}}Contract extends BaseContract { {{/each}} public static async deployFrom0xArtifactAsync( artifact: ContractArtifact | SimpleContractArtifact, - provider: Provider, + supportedProvider: SupportedProvider, txDefaults: Partial, {{> typed_params inputs=ctor.inputs}} ): Promise<{{contractName}}Contract> { if (_.isUndefined(artifact.compilerOutput)) { throw new Error('Compiler output not found in the artifact file'); } + const provider = providerUtils.standardizeOrThrow(supportedProvider); const bytecode = artifact.compilerOutput.evm.bytecode.object; const abi = artifact.compilerOutput.abi; return {{contractName}}Contract.deployAsync(bytecode, abi, provider, txDefaults, {{> params inputs=ctor.inputs}}); @@ -56,10 +57,11 @@ export class {{contractName}}Contract extends BaseContract { public static async deployAsync( bytecode: string, abi: ContractAbi, - provider: Provider, + supportedProvider: SupportedProvider, txDefaults: Partial, {{> typed_params inputs=ctor.inputs}} ): Promise<{{contractName}}Contract> { + const provider = providerUtils.standardizeOrThrow(supportedProvider); const constructorAbi = BaseContract._lookupConstructorAbi(abi); [{{> params inputs=ctor.inputs}}] = BaseContract._formatABIDataItemList( constructorAbi.inputs, @@ -83,8 +85,8 @@ export class {{contractName}}Contract extends BaseContract { contractInstance.constructorArgs = [{{> params inputs=ctor.inputs}}]; return contractInstance; } - constructor(abi: ContractAbi, address: string, provider: Provider, txDefaults?: Partial) { - super('{{contractName}}', abi, address, provider, txDefaults); + constructor(abi: ContractAbi, address: string, supportedProvider: SupportedProvider, txDefaults?: Partial) { + super('{{contractName}}', abi, address, providerUtils.standardizeOrThrow(supportedProvider), txDefaults); classUtils.bindAll(this, ['_abiEncoderByFunctionSignature', 'address', 'abi', '_web3Wrapper']); } } // tslint:disable:max-file-line-count diff --git a/packages/assert/src/index.ts b/packages/assert/src/index.ts index 0f05e3bd0b..e5a623ca82 100644 --- a/packages/assert/src/index.ts +++ b/packages/assert/src/index.ts @@ -59,6 +59,11 @@ export const assert = { isBoolean(variableName: string, value: boolean): void { assert.assert(_.isBoolean(value), assert.typeAssertionMessage(variableName, 'boolean', value)); }, + // DEPRECATED: Please use providerUtils.standardizeOrThrow() instead + isWeb3Provider(variableName: string, value: any): void { + const isWeb3Provider = _.isFunction(value.send) || _.isFunction(value.sendAsync); + assert.assert(isWeb3Provider, assert.typeAssertionMessage(variableName, 'Provider', value)); + }, doesConformToSchema(variableName: string, value: any, schema: Schema, subSchemas?: Schema[]): void { if (_.isUndefined(value)) { throw new Error(`${variableName} can't be undefined`); diff --git a/packages/asset-buyer/src/asset_buyer.ts b/packages/asset-buyer/src/asset_buyer.ts index 88972690a5..1599d50aec 100644 --- a/packages/asset-buyer/src/asset_buyer.ts +++ b/packages/asset-buyer/src/asset_buyer.ts @@ -4,7 +4,7 @@ import { SignedOrder } from '@0x/order-utils'; import { ObjectMap } from '@0x/types'; import { BigNumber, providerUtils } from '@0x/utils'; import { Web3Wrapper } from '@0x/web3-wrapper'; -import { Provider } from 'ethereum-types'; +import { Provider, SupportedProvider } from 'ethereum-types'; import * as _ from 'lodash'; import { constants } from './constants'; @@ -52,11 +52,11 @@ export class AssetBuyer { * @return An instance of AssetBuyer */ public static getAssetBuyerForProvidedOrders( - provider: Provider, + supportedProvider: SupportedProvider, orders: SignedOrder[], options: Partial = {}, ): AssetBuyer { - providerUtils.standardizeOrThrow(provider); + const provider = providerUtils.standardizeOrThrow(supportedProvider); assert.doesConformToSchema('orders', orders, schemas.signedOrdersSchema); assert.assert(orders.length !== 0, `Expected orders to contain at least one order`); const orderProvider = new BasicOrderProvider(orders); @@ -72,11 +72,11 @@ export class AssetBuyer { * @return An instance of AssetBuyer */ public static getAssetBuyerForStandardRelayerAPIUrl( - provider: Provider, + supportedProvider: SupportedProvider, sraApiUrl: string, options: Partial = {}, ): AssetBuyer { - providerUtils.standardizeOrThrow(provider); + const provider = providerUtils.standardizeOrThrow(supportedProvider); assert.isWebUri('sraApiUrl', sraApiUrl); const networkId = options.networkId || constants.DEFAULT_ASSET_BUYER_OPTS.networkId; const orderProvider = new StandardRelayerAPIOrderProvider(sraApiUrl, networkId); @@ -91,13 +91,13 @@ export class AssetBuyer { * * @return An instance of AssetBuyer */ - constructor(provider: Provider, orderProvider: OrderProvider, options: Partial = {}) { + constructor(supportedProvider: SupportedProvider, orderProvider: OrderProvider, options: Partial = {}) { const { networkId, orderRefreshIntervalMs, expiryBufferSeconds } = _.merge( {}, constants.DEFAULT_ASSET_BUYER_OPTS, options, ); - providerUtils.standardizeOrThrow(provider); + const provider = providerUtils.standardizeOrThrow(supportedProvider); assert.isValidOrderProvider('orderProvider', orderProvider); assert.isNumber('networkId', networkId); assert.isNumber('orderRefreshIntervalMs', orderRefreshIntervalMs); diff --git a/packages/base-contract/src/index.ts b/packages/base-contract/src/index.ts index f6f5a4fc17..0238106f32 100644 --- a/packages/base-contract/src/index.ts +++ b/packages/base-contract/src/index.ts @@ -1,4 +1,4 @@ -import { AbiEncoder, abiUtils, BigNumber, providerUtils } from '@0x/utils'; +import { AbiEncoder, abiUtils, BigNumber } from '@0x/utils'; import { Web3Wrapper } from '@0x/web3-wrapper'; import { AbiDefinition, @@ -157,9 +157,8 @@ export class BaseContract { provider: Provider, txDefaults?: Partial, ) { - const web3WrapperProvider = providerUtils.standardizeOrThrow(provider); this.contractName = contractName; - this._web3Wrapper = new Web3Wrapper(web3WrapperProvider, txDefaults); + this._web3Wrapper = new Web3Wrapper(provider, txDefaults); this.abi = abi; this.address = address; const methodAbis = this.abi.filter( diff --git a/packages/ethereum-types/src/index.ts b/packages/ethereum-types/src/index.ts index d98245136c..8367ec9066 100644 --- a/packages/ethereum-types/src/index.ts +++ b/packages/ethereum-types/src/index.ts @@ -6,7 +6,7 @@ export type JSONRPCErrorCallback = (err: Error | null, result?: JSONRPCResponseP * Do not create your own provider. Use an existing provider from a Web3 or ProviderEngine library * Read more about Providers in the 0x wiki. */ -export type Provider = Web3JsProvider | Web3WrapperProvider | EIP1193Provider; +export type SupportedProvider = Web3JsProvider | Provider | EIP1193Provider; export type Web3JsProvider = Web3JsV1Provider | Web3JsV2Provider | Web3JsV3Provider; @@ -22,12 +22,12 @@ export interface Web3JsV3Provider { /** * The interface for the provider used by @0x/web3-wrapper */ -export interface Web3WrapperProvider { +export interface Provider { sendAsync(payload: JSONRPCRequestPayload, callback: JSONRPCErrorCallback): void; } -export type GanacheProvider = Web3WrapperProvider; -export type ProviderEngineProvider = Web3WrapperProvider; +export type GanacheProvider = Provider; +export type ProviderEngineProvider = Provider; /** * Web3.js version 1 provider interface diff --git a/packages/order-utils/src/order_validation_utils.ts b/packages/order-utils/src/order_validation_utils.ts index 95215d9188..0ba1ab43db 100644 --- a/packages/order-utils/src/order_validation_utils.ts +++ b/packages/order-utils/src/order_validation_utils.ts @@ -1,6 +1,6 @@ import { ExchangeContractErrs, RevertReason, SignedOrder } from '@0x/types'; -import { BigNumber } from '@0x/utils'; -import { Provider } from 'ethereum-types'; +import { BigNumber, providerUtils } from '@0x/utils'; +import { Provider, SupportedProvider } from 'ethereum-types'; import * as _ from 'lodash'; import { OrderError, TradeSide, TransferType } from './types'; @@ -185,7 +185,7 @@ export class OrderValidationUtils { */ public async validateFillOrderThrowIfInvalidAsync( exchangeTradeEmulator: ExchangeTransferSimulator, - provider: Provider, + supportedProvider: SupportedProvider, signedOrder: SignedOrder, fillTakerAssetAmount: BigNumber, takerAddress: string, @@ -197,6 +197,7 @@ export class OrderValidationUtils { if (fillTakerAssetAmount.eq(0)) { throw new Error(RevertReason.InvalidTakerAmount); } + const provider = providerUtils.standardizeOrThrow(supportedProvider); const orderHash = orderHashUtils.getOrderHashHex(signedOrder); const isValid = await signatureUtils.isValidSignatureAsync( provider, diff --git a/packages/subproviders/src/index.ts b/packages/subproviders/src/index.ts index 050027f96d..26095938f9 100644 --- a/packages/subproviders/src/index.ts +++ b/packages/subproviders/src/index.ts @@ -53,6 +53,7 @@ export { ECSignature, EIP712Object, EIP712ObjectValue, EIP712TypedData, EIP712Ty export { JSONRPCRequestPayload, Provider, + SupportedProvider, JSONRPCResponsePayload, JSONRPCErrorCallback, JSONRPCResponseError, diff --git a/packages/subproviders/src/subproviders/metamask_subprovider.ts b/packages/subproviders/src/subproviders/metamask_subprovider.ts index a9d9117785..de914056d0 100644 --- a/packages/subproviders/src/subproviders/metamask_subprovider.ts +++ b/packages/subproviders/src/subproviders/metamask_subprovider.ts @@ -1,6 +1,6 @@ import { providerUtils } from '@0x/utils'; import { marshaller, Web3Wrapper } from '@0x/web3-wrapper'; -import { JSONRPCRequestPayload, Web3WrapperProvider } from 'ethereum-types'; +import { JSONRPCRequestPayload, Provider, SupportedProvider } from 'ethereum-types'; import * as ethUtil from 'ethereumjs-util'; import { Callback, ErrorCallback } from '../types'; @@ -17,16 +17,16 @@ import { Subprovider } from './subprovider'; */ export class MetamaskSubprovider extends Subprovider { private readonly _web3Wrapper: Web3Wrapper; - private readonly _provider: Web3WrapperProvider; + private readonly _provider: Provider; /** * Instantiates a new MetamaskSubprovider * @param provider Web3 provider that should handle all user account related requests */ - constructor(provider: Web3WrapperProvider) { + constructor(supportedProvider: SupportedProvider) { super(); + const provider = providerUtils.standardizeOrThrow(supportedProvider); this._web3Wrapper = new Web3Wrapper(provider); - const web3WrapperProvider = providerUtils.standardizeOrThrow(provider); - this._provider = web3WrapperProvider; + this._provider = provider; } /** * This method conforms to the web3-provider-engine interface. diff --git a/packages/utils/src/provider_utils.ts b/packages/utils/src/provider_utils.ts index ff928dd86e..4f1a2752c7 100644 --- a/packages/utils/src/provider_utils.ts +++ b/packages/utils/src/provider_utils.ts @@ -3,18 +3,24 @@ import { JSONRPCErrorCallback, JSONRPCRequestPayload, Provider, - Web3WrapperProvider, + SupportedProvider, } from 'ethereum-types'; import * as _ from 'lodash'; export const providerUtils = { - standardizeOrThrow(provider: Provider): Web3WrapperProvider { - if ((provider as EIP1193Provider).isEIP1193) { - const web3WrapperProvider: Web3WrapperProvider = { + /** + * Standardize the supported provider types into our internal provider interface + * or throw if unsupported provider supplied. + * @param supportedProvider Potentially supported provider instance + * @return Provider that conforms of our internal provider interface + */ + standardizeOrThrow(supportedProvider: SupportedProvider): Provider { + if ((supportedProvider as EIP1193Provider).isEIP1193) { + const provider: Provider = { sendAsync: (payload: JSONRPCRequestPayload, callback: JSONRPCErrorCallback) => { const method = payload.method; const params = payload.params; - (provider as EIP1193Provider) + (supportedProvider as EIP1193Provider) .send(method, params) .then((result: any) => { callback(null, result); @@ -24,27 +30,26 @@ export const providerUtils = { }); }, }; - return web3WrapperProvider; - } else if (_.isUndefined((provider as any).sendAsync)) { - // Web3@1.0 provider doesn't support synchronous http requests, - // so it only has an async `send` method, instead of a `send` and `sendAsync` in web3@0.x.x` - // We re-assign the send method so that Web3@1.0 providers work with @0x/web3-wrapper - const web3WrapperProvider: Web3WrapperProvider = { - sendAsync: (provider as any).send, + return provider; + } else if (_.isUndefined((supportedProvider as any).sendAsync)) { + // An early version of Web3@1.0 Beta provider only has an async `send` method so + // we re-assign the send method so that early Web3@1.0 Beta providers work with @0x/web3-wrapper + const provider: Provider = { + sendAsync: (supportedProvider as any).send, }; - return web3WrapperProvider; - } else if (!_.isUndefined((provider as any).sendAsync)) { - return provider as Web3WrapperProvider; - } else if ((provider as any).host) { - // HACK(fabio): Web3 1.0 Beta modified their `send` method to comply with EIP1193 but did not add the - // `isEIP1193` flag. The only common identifier across Web3 providers is that they all have + return provider; + } else if (!_.isUndefined((supportedProvider as any).sendAsync)) { + return supportedProvider as Provider; + } else if ((supportedProvider as any).host) { + // HACK(fabio): Later Web3@1.0 Beta modified their `send` method to comply with EIP1193 but did not add the + // `isEIP1193` flag. The only common identifier across Web3.js providers is that they all have // a `host` property, so we check for it's existence. We put this check last to make it less likely // that this condition is hit for other providers that also expose a `host` property. - const web3WrapperProvider: Web3WrapperProvider = { + const provider: Provider = { sendAsync: (payload: JSONRPCRequestPayload, callback: JSONRPCErrorCallback) => { const method = payload.method; const params = payload.params; - (provider as any) + (supportedProvider as any) .send(method, params) .then((result: any) => { callback(null, result); @@ -54,7 +59,7 @@ export const providerUtils = { }); }, }; - return web3WrapperProvider; + return provider; } throw new Error( `Unsupported provider found. Please make sure it conforms to one of the supported providers. See 'Provider' type in 'ethereum-types' package.`, diff --git a/packages/web3-wrapper/src/web3_wrapper.ts b/packages/web3-wrapper/src/web3_wrapper.ts index c8b88d63dc..a680c3fdd3 100644 --- a/packages/web3-wrapper/src/web3_wrapper.ts +++ b/packages/web3-wrapper/src/web3_wrapper.ts @@ -13,13 +13,13 @@ import { LogEntry, Provider, RawLogEntry, + SupportedProvider, TraceParams, Transaction, TransactionReceipt, TransactionReceiptWithDecodedLogs, TransactionTrace, TxData, - Web3WrapperProvider, } from 'ethereum-types'; import * as _ from 'lodash'; @@ -52,7 +52,7 @@ export class Web3Wrapper { */ public isZeroExWeb3Wrapper = true; public abiDecoder: AbiDecoder; - private _provider: Web3WrapperProvider; + private _provider: Provider; private readonly _txDefaults: Partial; private _jsonRpcRequestId: number; /** @@ -148,10 +148,10 @@ export class Web3Wrapper { * @param txDefaults Override TxData defaults sent with RPC requests to the backing Ethereum node. * @return An instance of the Web3Wrapper class. */ - constructor(provider: Provider, txDefaults?: Partial) { - const web3WrapperProvider = providerUtils.standardizeOrThrow(provider); + constructor(supportedProvider: SupportedProvider, txDefaults?: Partial) { + const provider = providerUtils.standardizeOrThrow(supportedProvider); this.abiDecoder = new AbiDecoder([]); - this._provider = web3WrapperProvider; + this._provider = provider; this._txDefaults = txDefaults || {}; this._jsonRpcRequestId = 1; } @@ -173,9 +173,9 @@ export class Web3Wrapper { * Update the used Web3 provider * @param provider The new Web3 provider to be set */ - public setProvider(provider: Provider): void { - const web3WrapperProvider = providerUtils.standardizeOrThrow(provider); - this._provider = web3WrapperProvider; + public setProvider(supportedProvider: SupportedProvider): void { + const provider = providerUtils.standardizeOrThrow(supportedProvider); + this._provider = provider; } /** * Check whether an address is available through the backing provider. This can be