Merge pull request #385 from 0xProject/feature/0x_config_validation

Better validate ZeroExConfig on private networks
This commit is contained in:
Leonid Logvinov 2018-02-23 13:20:28 -08:00 committed by GitHub
commit 10c0c0b6d2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 92 additions and 31 deletions

View File

@ -1,5 +1,9 @@
# CHANGELOG # CHANGELOG
## v0.33.0 - _TBD, 2018_
* Improve validation to force passing contract addresses on private networks (#385)
## v0.32.2 - _February 9, 2018_ ## v0.32.2 - _February 9, 2018_
* Fix publishing issue where .npmignore was not properly excluding undesired content (#389) * Fix publishing issue where .npmignore was not properly excluding undesired content (#389)

View File

@ -13,6 +13,8 @@ import { TokenTransferProxyWrapper } from './contract_wrappers/token_transfer_pr
import { TokenWrapper } from './contract_wrappers/token_wrapper'; import { TokenWrapper } from './contract_wrappers/token_wrapper';
import { OrderStateWatcher } from './order_watcher/order_state_watcher'; import { OrderStateWatcher } from './order_watcher/order_state_watcher';
import { zeroExConfigSchema } from './schemas/zero_ex_config_schema'; import { zeroExConfigSchema } from './schemas/zero_ex_config_schema';
import { zeroExPrivateNetworkConfigSchema } from './schemas/zero_ex_private_network_config_schema';
import { zeroExPublicNetworkConfigSchema } from './schemas/zero_ex_public_network_config_schema';
import { ECSignature, Order, SignedOrder, Web3Provider, ZeroExConfig, ZeroExError } from './types'; import { ECSignature, Order, SignedOrder, Web3Provider, ZeroExConfig, ZeroExError } from './types';
import { assert } from './utils/assert'; import { assert } from './utils/assert';
import { constants } from './utils/constants'; import { constants } from './utils/constants';
@ -163,7 +165,10 @@ export class ZeroEx {
*/ */
constructor(provider: Web3Provider, config: ZeroExConfig) { constructor(provider: Web3Provider, config: ZeroExConfig) {
assert.isWeb3Provider('provider', provider); assert.isWeb3Provider('provider', provider);
assert.doesConformToSchema('config', config, zeroExConfigSchema); assert.doesConformToSchema('config', config, zeroExConfigSchema, [
zeroExPrivateNetworkConfigSchema,
zeroExPublicNetworkConfigSchema,
]);
const artifactJSONs = _.values(artifacts); const artifactJSONs = _.values(artifacts);
const abiArrays = _.map(artifactJSONs, artifact => artifact.abi); const abiArrays = _.map(artifactJSONs, artifact => artifact.abi);
this._abiDecoder = new AbiDecoder(abiArrays); this._abiDecoder = new AbiDecoder(abiArrays);

View File

@ -1,27 +1,5 @@
export const zeroExConfigSchema = { export const zeroExConfigSchema = {
id: '/ZeroExConfig', id: '/ZeroExConfig',
properties: { oneOf: [{ $ref: '/ZeroExPrivateNetworkConfig' }, { $ref: '/ZeroExPublicNetworkConfig' }],
networkId: {
type: 'number',
minimum: 0,
},
gasPrice: { $ref: '/Number' },
exchangeContractAddress: { $ref: '/Address' },
tokenRegistryContractAddress: { $ref: '/Address' },
orderWatcherConfig: {
type: 'object', type: 'object',
properties: {
pollingIntervalMs: {
type: 'number',
minimum: 0,
},
numConfirmations: {
type: 'number',
minimum: 0,
},
},
},
},
type: 'object',
required: ['networkId'],
}; };

View File

@ -0,0 +1,35 @@
export const zeroExPrivateNetworkConfigSchema = {
id: '/ZeroExPrivateNetworkConfig',
properties: {
networkId: {
type: 'number',
minimum: 1,
},
gasPrice: { $ref: '/Number' },
zrxContractAddress: { $ref: '/Address' },
exchangeContractAddress: { $ref: '/Address' },
tokenRegistryContractAddress: { $ref: '/Address' },
tokenTransferProxyContractAddress: { $ref: '/Address' },
orderWatcherConfig: {
type: 'object',
properties: {
pollingIntervalMs: {
type: 'number',
minimum: 0,
},
numConfirmations: {
type: 'number',
minimum: 0,
},
},
},
},
type: 'object',
required: [
'networkId',
'zrxContractAddress',
'exchangeContractAddress',
'tokenRegistryContractAddress',
'tokenTransferProxyContractAddress',
],
};

View File

@ -0,0 +1,29 @@
export const zeroExPublicNetworkConfigSchema = {
id: '/ZeroExPublicNetworkConfig',
properties: {
networkId: {
type: 'number',
enum: [1, 3, 4, 42, 50],
},
gasPrice: { $ref: '/Number' },
zrxContractAddress: { $ref: '/Address' },
exchangeContractAddress: { $ref: '/Address' },
tokenRegistryContractAddress: { $ref: '/Address' },
tokenTransferProxyContractAddress: { $ref: '/Address' },
orderWatcherConfig: {
type: 'object',
properties: {
pollingIntervalMs: {
type: 'number',
minimum: 0,
},
numConfirmations: {
type: 'number',
minimum: 0,
},
},
},
},
type: 'object',
required: ['networkId'],
};

View File

@ -196,7 +196,7 @@ export interface OrderStateWatcherConfig {
} }
/* /*
* networkId: The id of the underlying ethereum network your provider is connected to. (1-mainnet, 42-kovan, 50-testrpc) * networkId: The id of the underlying ethereum network your provider is connected to. (1-mainnet, 3-ropsten, 4-rinkeby, 42-kovan, 50-testrpc)
* gasPrice: Gas price to use with every transaction * gasPrice: Gas price to use with every transaction
* exchangeContractAddress: The address of an exchange contract to use * exchangeContractAddress: The address of an exchange contract to use
* zrxContractAddress: The address of the ZRX contract to use * zrxContractAddress: The address of the ZRX contract to use

View File

@ -75,11 +75,14 @@ describe('EtherTokenWrapper', () => {
const contractAddressIfExists = zeroEx.etherToken.getContractAddressIfExists(); const contractAddressIfExists = zeroEx.etherToken.getContractAddressIfExists();
expect(contractAddressIfExists).to.not.be.undefined(); expect(contractAddressIfExists).to.not.be.undefined();
}); });
it('should return undefined if connected to an unknown network', () => { it('should throw if connected to a private network and contract addresses are not specified', () => {
const UNKNOWN_NETWORK_NETWORK_ID = 10; const UNKNOWN_NETWORK_NETWORK_ID = 10;
const unknownNetworkZeroEx = new ZeroEx(web3.currentProvider, { networkId: UNKNOWN_NETWORK_NETWORK_ID }); expect(
const contractAddressIfExists = unknownNetworkZeroEx.etherToken.getContractAddressIfExists(); () =>
expect(contractAddressIfExists).to.be.undefined(); new ZeroEx(web3.currentProvider, {
networkId: UNKNOWN_NETWORK_NETWORK_ID,
} as any),
).to.throw();
}); });
}); });
describe('#depositAsync', () => { describe('#depositAsync', () => {

View File

@ -9,10 +9,10 @@ import * as Web3 from 'web3';
import { ZeroEx } from '../src/0x'; import { ZeroEx } from '../src/0x';
import { ExpirationWatcher } from '../src/order_watcher/expiration_watcher'; import { ExpirationWatcher } from '../src/order_watcher/expiration_watcher';
import { DoneCallback, Token } from '../src/types'; import { DoneCallback, Token } from '../src/types';
import { constants } from '../src/utils/constants';
import { utils } from '../src/utils/utils'; import { utils } from '../src/utils/utils';
import { chaiSetup } from './utils/chai_setup'; import { chaiSetup } from './utils/chai_setup';
import { constants } from './utils/constants';
import { FillScenarios } from './utils/fill_scenarios'; import { FillScenarios } from './utils/fill_scenarios';
import { reportNoErrorCallbackErrors } from './utils/report_callback_errors'; import { reportNoErrorCallbackErrors } from './utils/report_callback_errors';
import { TokenUtils } from './utils/token_utils'; import { TokenUtils } from './utils/token_utils';

View File

@ -1,5 +1,9 @@
# CHANGELOG # CHANGELOG
## v0.1.0 - _TBD, 2018_
* Add an optional parameter `subSchemas` to `doesConformToSchema` method (#385)
## v0.0.18 - _February 9, 2017_ ## v0.0.18 - _February 9, 2017_
* Fix publishing issue where .npmignore was not properly excluding undesired content (#389) * Fix publishing issue where .npmignore was not properly excluding undesired content (#389)

View File

@ -66,8 +66,11 @@ export const assert = {
const isWeb3Provider = _.isFunction(value.send) || _.isFunction(value.sendAsync); const isWeb3Provider = _.isFunction(value.send) || _.isFunction(value.sendAsync);
this.assert(isWeb3Provider, this.typeAssertionMessage(variableName, 'Web3.Provider', value)); this.assert(isWeb3Provider, this.typeAssertionMessage(variableName, 'Web3.Provider', value));
}, },
doesConformToSchema(variableName: string, value: any, schema: Schema): void { doesConformToSchema(variableName: string, value: any, schema: Schema, subSchemas?: Schema[]): void {
const schemaValidator = new SchemaValidator(); const schemaValidator = new SchemaValidator();
if (!_.isUndefined(subSchemas)) {
_.map(subSchemas, schemaValidator.addSchema.bind(schemaValidator));
}
const validationResult = schemaValidator.validate(value, schema); const validationResult = schemaValidator.validate(value, schema);
const hasValidationErrors = validationResult.errors.length > 0; const hasValidationErrors = validationResult.errors.length > 0;
const msg = `Expected ${variableName} to conform to schema ${schema.id} const msg = `Expected ${variableName} to conform to schema ${schema.id}