Add json-schemas package to mono repo
This commit is contained in:
parent
08963f269b
commit
56b5619d24
@ -88,7 +88,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@0xproject/assert": "0.0.3",
|
||||
"0x-json-schemas": "^0.6.1",
|
||||
"@0xproject/json-schemas": "0.6.6",
|
||||
"bignumber.js": "~4.1.0",
|
||||
"compare-versions": "^3.0.1",
|
||||
"es6-promisify": "^5.0.0",
|
||||
|
@ -1,6 +1,6 @@
|
||||
import * as _ from 'lodash';
|
||||
import BigNumber from 'bignumber.js';
|
||||
import {SchemaValidator, schemas} from '0x-json-schemas';
|
||||
import {SchemaValidator, schemas} from '@0xproject/json-schemas';
|
||||
import {bigNumberConfigs} from './bignumber_config';
|
||||
import * as ethUtil from 'ethereumjs-util';
|
||||
import {Web3Wrapper} from './web3_wrapper';
|
||||
|
@ -1,7 +1,7 @@
|
||||
import * as Web3 from 'web3';
|
||||
import * as _ from 'lodash';
|
||||
import promisify = require('es6-promisify');
|
||||
import {SchemaValidator, schemas} from '0x-json-schemas';
|
||||
import {SchemaValidator, schemas} from '@0xproject/json-schemas';
|
||||
import {AbiType} from './types';
|
||||
|
||||
export class Contract implements Web3.ContractInstance {
|
||||
|
@ -1,7 +1,7 @@
|
||||
import * as _ from 'lodash';
|
||||
import * as Web3 from 'web3';
|
||||
import BigNumber from 'bignumber.js';
|
||||
import {schemas} from '0x-json-schemas';
|
||||
import {schemas} from '@0xproject/json-schemas';
|
||||
import {Web3Wrapper} from '../web3_wrapper';
|
||||
import {
|
||||
ECSignature,
|
||||
|
@ -1,6 +1,6 @@
|
||||
import * as _ from 'lodash';
|
||||
import BigNumber from 'bignumber.js';
|
||||
import {schemas} from '0x-json-schemas';
|
||||
import {schemas} from '@0xproject/json-schemas';
|
||||
import {Web3Wrapper} from '../web3_wrapper';
|
||||
import {assert} from '../utils/assert';
|
||||
import {constants} from '../utils/constants';
|
||||
|
@ -1,5 +1,5 @@
|
||||
import * as _ from 'lodash';
|
||||
import {schemas} from '0x-json-schemas';
|
||||
import {schemas} from '@0xproject/json-schemas';
|
||||
import {ZeroEx} from '../0x';
|
||||
import {EventWatcher} from './event_watcher';
|
||||
import {assert} from '../utils/assert';
|
||||
|
@ -1,7 +1,7 @@
|
||||
import * as _ from 'lodash';
|
||||
import * as Web3 from 'web3';
|
||||
import BigNumber from 'bignumber.js';
|
||||
import {SchemaValidator, Schema} from '0x-json-schemas';
|
||||
import {SchemaValidator, Schema} from '@0xproject/json-schemas';
|
||||
import {assert as sharedAssert} from '@0xproject/assert';
|
||||
import {Web3Wrapper} from '../web3_wrapper';
|
||||
import {signatureUtils} from '../utils/signature_utils';
|
||||
|
@ -1,7 +1,7 @@
|
||||
import * as _ from 'lodash';
|
||||
import 'mocha';
|
||||
import * as chai from 'chai';
|
||||
import {SchemaValidator, schemas} from '0x-json-schemas';
|
||||
import {SchemaValidator, schemas} from '@0xproject/json-schemas';
|
||||
import {chaiSetup} from './utils/chai_setup';
|
||||
import {web3Factory} from './utils/web3_factory';
|
||||
import {ZeroEx, Token} from '../src';
|
||||
|
@ -38,7 +38,7 @@
|
||||
"typescript": "^2.4.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"0x-json-schemas": "^0.6.5",
|
||||
"@0xproject/json-schemas": "0.6.6",
|
||||
"bignumber.js": "~4.1.0",
|
||||
"ethereum-address": "^0.0.4",
|
||||
"lodash": "^4.17.4",
|
||||
|
@ -2,7 +2,10 @@ import BigNumber from 'bignumber.js';
|
||||
import * as ethereum_address from 'ethereum-address';
|
||||
import * as _ from 'lodash';
|
||||
import * as validUrl from 'valid-url';
|
||||
import {SchemaValidator, Schema} from '0x-json-schemas';
|
||||
import {
|
||||
SchemaValidator,
|
||||
Schema,
|
||||
} from '@0xproject/json-schemas';
|
||||
|
||||
const HEX_REGEX = /^0x[0-9A-F]*$/i;
|
||||
|
||||
|
@ -2,7 +2,7 @@ import 'mocha';
|
||||
import * as dirtyChai from 'dirty-chai';
|
||||
import * as chai from 'chai';
|
||||
import {BigNumber} from 'bignumber.js';
|
||||
import {schemas} from '0x-json-schemas';
|
||||
import {schemas} from '@0xproject/json-schemas';
|
||||
import {assert} from '../src/index';
|
||||
|
||||
chai.config.includeStack = true;
|
||||
|
15
packages/json-schemas/README.md
Normal file
15
packages/json-schemas/README.md
Normal file
@ -0,0 +1,15 @@
|
||||
Contains 0x-related json schemas
|
||||
|
||||
## Usage:
|
||||
```
|
||||
import {SchemaValidator, ValidatorResult, schemas} from '@0xproject/json-schemas';
|
||||
|
||||
const {orderSchema} = schemas;
|
||||
const validator = new SchemaValidator();
|
||||
|
||||
const order = {
|
||||
...
|
||||
};
|
||||
const validatorResult: ValidatorResult = validator.validate(order, orderSchema); // Contains all errors
|
||||
const isValid: boolean = validator.isValid(order, orderSchema); // Only returns boolean
|
||||
```
|
45
packages/json-schemas/package.json
Normal file
45
packages/json-schemas/package.json
Normal file
@ -0,0 +1,45 @@
|
||||
{
|
||||
"name": "@0xproject/json-schemas",
|
||||
"version": "0.6.6",
|
||||
"description": "0x-related json schemas",
|
||||
"main": "lib/src/index.js",
|
||||
"types": "lib/src/index.d.ts",
|
||||
"scripts": {
|
||||
"lint": "tslint src/*.ts test/*.ts",
|
||||
"test": "run-s clean build run_mocha",
|
||||
"test:circleci": "yarn test",
|
||||
"run_mocha": "mocha lib/test/**/*_test.js",
|
||||
"clean": "shx rm -rf _bundles lib test_temp",
|
||||
"build": "tsc"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/0xProject/0x.js.git"
|
||||
},
|
||||
"author": "",
|
||||
"license": "Apache-2.0",
|
||||
"bugs": {
|
||||
"url": "https://github.com/0xProject/0x.js/issues"
|
||||
},
|
||||
"homepage": "https://github.com/0xProject/0x.js/packages/json-schemas/README.md",
|
||||
"dependencies": {
|
||||
"jsonschema": "^1.2.0",
|
||||
"lodash.values": "^4.3.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/lodash.foreach": "^4.5.3",
|
||||
"@types/lodash.values": "^4.3.3",
|
||||
"@types/mocha": "^2.2.42",
|
||||
"bignumber.js": "^4.0.2",
|
||||
"chai": "^4.1.1",
|
||||
"chai-typescript-typings": "^0.0.1",
|
||||
"dirty-chai": "^2.0.1",
|
||||
"lodash.foreach": "^4.5.0",
|
||||
"mocha": "^4.0.1",
|
||||
"npm-run-all": "^4.1.1",
|
||||
"shx": "^0.2.2",
|
||||
"tslint": "~5.5.0",
|
||||
"tslint-config-0xproject": "^0.0.2",
|
||||
"typescript": "^2.4.2"
|
||||
}
|
||||
}
|
11
packages/json-schemas/schemas/basic_type_schemas.ts
Normal file
11
packages/json-schemas/schemas/basic_type_schemas.ts
Normal file
@ -0,0 +1,11 @@
|
||||
export const addressSchema = {
|
||||
id: '/Address',
|
||||
type: 'string',
|
||||
pattern: '^0x[0-9a-f]{40}$',
|
||||
};
|
||||
|
||||
export const numberSchema = {
|
||||
id: '/Number',
|
||||
type: 'string',
|
||||
pattern: '^\\d+(\\.\\d+)?$',
|
||||
};
|
20
packages/json-schemas/schemas/ec_signature_schema.ts
Normal file
20
packages/json-schemas/schemas/ec_signature_schema.ts
Normal file
@ -0,0 +1,20 @@
|
||||
export const ecSignatureParameterSchema = {
|
||||
id: '/ECSignatureParameter',
|
||||
type: 'string',
|
||||
pattern: '^0[xX][0-9A-Fa-f]{64}$',
|
||||
};
|
||||
|
||||
export const ecSignatureSchema = {
|
||||
id: '/ECSignature',
|
||||
properties: {
|
||||
v: {
|
||||
type: 'number',
|
||||
minimum: 27,
|
||||
maximum: 28,
|
||||
},
|
||||
r: {$ref: '/ECSignatureParameter'},
|
||||
s: {$ref: '/ECSignatureParameter'},
|
||||
},
|
||||
required: ['v', 'r', 's'],
|
||||
type: 'object',
|
||||
};
|
11
packages/json-schemas/schemas/index_filter_values_schema.ts
Normal file
11
packages/json-schemas/schemas/index_filter_values_schema.ts
Normal file
@ -0,0 +1,11 @@
|
||||
export const indexFilterValuesSchema = {
|
||||
id: '/IndexFilterValues',
|
||||
additionalProperties: {
|
||||
oneOf: [
|
||||
{$ref: '/Number'},
|
||||
{$ref: '/Address'},
|
||||
{$ref: '/OrderHashSchema'},
|
||||
],
|
||||
},
|
||||
type: 'object',
|
||||
};
|
12
packages/json-schemas/schemas/order_cancel_schema.ts
Normal file
12
packages/json-schemas/schemas/order_cancel_schema.ts
Normal file
@ -0,0 +1,12 @@
|
||||
export const orderCancellationRequestsSchema = {
|
||||
id: '/OrderCancellationRequests',
|
||||
type: 'array',
|
||||
items: {
|
||||
properties: {
|
||||
order: {$ref: '/Order'},
|
||||
takerTokenCancelAmount: {$ref: '/Number'},
|
||||
},
|
||||
required: ['order', 'takerTokenCancelAmount'],
|
||||
type: 'object',
|
||||
},
|
||||
};
|
@ -0,0 +1,12 @@
|
||||
export const orderFillOrKillRequestsSchema = {
|
||||
id: '/OrderFillOrKillRequests',
|
||||
type: 'array',
|
||||
items: {
|
||||
properties: {
|
||||
signedOrder: {$ref: '/SignedOrder'},
|
||||
fillTakerAmount: {$ref: '/Number'},
|
||||
},
|
||||
required: ['signedOrder', 'fillTakerAmount'],
|
||||
type: 'object',
|
||||
},
|
||||
};
|
12
packages/json-schemas/schemas/order_fill_requests_schema.ts
Normal file
12
packages/json-schemas/schemas/order_fill_requests_schema.ts
Normal file
@ -0,0 +1,12 @@
|
||||
export const orderFillRequestsSchema = {
|
||||
id: '/OrderFillRequests',
|
||||
type: 'array',
|
||||
items: {
|
||||
properties: {
|
||||
signedOrder: {$ref: '/SignedOrder'},
|
||||
takerTokenFillAmount: {$ref: '/Number'},
|
||||
},
|
||||
required: ['signedOrder', 'takerTokenFillAmount'],
|
||||
type: 'object',
|
||||
},
|
||||
};
|
5
packages/json-schemas/schemas/order_hash_schema.ts
Normal file
5
packages/json-schemas/schemas/order_hash_schema.ts
Normal file
@ -0,0 +1,5 @@
|
||||
export const orderHashSchema = {
|
||||
id: '/OrderHashSchema',
|
||||
type: 'string',
|
||||
pattern: '^0x[0-9a-fA-F]{64}$',
|
||||
};
|
35
packages/json-schemas/schemas/order_schemas.ts
Normal file
35
packages/json-schemas/schemas/order_schemas.ts
Normal file
@ -0,0 +1,35 @@
|
||||
export const orderSchema = {
|
||||
id: '/Order',
|
||||
properties: {
|
||||
maker: {$ref: '/Address'},
|
||||
taker: {$ref: '/Address'},
|
||||
makerFee: {$ref: '/Number'},
|
||||
takerFee: {$ref: '/Number'},
|
||||
makerTokenAmount: {$ref: '/Number'},
|
||||
takerTokenAmount: {$ref: '/Number'},
|
||||
makerTokenAddress: {$ref: '/Address'},
|
||||
takerTokenAddress: {$ref: '/Address'},
|
||||
salt: {$ref: '/Number'},
|
||||
feeRecipient: {$ref: '/Address'},
|
||||
expirationUnixTimestampSec: {$ref: '/Number'},
|
||||
exchangeContractAddress: {$ref: '/Address'},
|
||||
},
|
||||
required: [
|
||||
'maker', 'taker', 'makerFee', 'takerFee', 'makerTokenAmount', 'takerTokenAmount',
|
||||
'salt', 'feeRecipient', 'expirationUnixTimestampSec', 'exchangeContractAddress',
|
||||
],
|
||||
type: 'object',
|
||||
};
|
||||
|
||||
export const signedOrderSchema = {
|
||||
id: '/SignedOrder',
|
||||
allOf: [
|
||||
{ $ref: '/Order' },
|
||||
{
|
||||
properties: {
|
||||
ecSignature: {$ref: '/ECSignature'},
|
||||
},
|
||||
required: ['ecSignature'],
|
||||
},
|
||||
],
|
||||
};
|
@ -0,0 +1,21 @@
|
||||
export const relayerApiErrorResponseSchema = {
|
||||
id: '/RelayerApiErrorResponse',
|
||||
type: 'object',
|
||||
properties: {
|
||||
code: {type: 'number'},
|
||||
reason: {type: 'string'},
|
||||
validationErrors: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
field: {type: 'string'},
|
||||
code: {type: 'number'},
|
||||
reason: {type: 'string'},
|
||||
},
|
||||
required: ['field', 'code', 'reason'],
|
||||
},
|
||||
},
|
||||
},
|
||||
required: ['code', 'reason'],
|
||||
};
|
@ -0,0 +1,19 @@
|
||||
export const relayerApiFeesPayloadSchema = {
|
||||
id: '/RelayerApiFeesPayload',
|
||||
type: 'object',
|
||||
properties: {
|
||||
exchangeContractAddress: {$ref: '/Address'},
|
||||
maker: {$ref: '/Address'},
|
||||
taker: {$ref: '/Address'},
|
||||
makerTokenAddress: {$ref: '/Address'},
|
||||
takerTokenAddress: {$ref: '/Address'},
|
||||
makerTokenAmount: {$ref: '/Number'},
|
||||
takerTokenAmount: {$ref: '/Number'},
|
||||
expirationUnixTimestampSec: {$ref: '/Number'},
|
||||
salt: {$ref: '/Number'},
|
||||
},
|
||||
required: [
|
||||
'exchangeContractAddress', 'maker', 'taker', 'makerTokenAddress', 'takerTokenAddress',
|
||||
'expirationUnixTimestampSec', 'salt',
|
||||
],
|
||||
};
|
@ -0,0 +1,10 @@
|
||||
export const relayerApiFeesResponseSchema = {
|
||||
id: '/RelayerApiFeesResponse',
|
||||
type: 'object',
|
||||
properties: {
|
||||
makerFee: {$ref: '/Number'},
|
||||
takerFee: {$ref: '/Number'},
|
||||
feeRecipient: {$ref: '/Address'},
|
||||
},
|
||||
required: ['makerFee', 'takerFee', 'feeRecipient'],
|
||||
};
|
@ -0,0 +1,22 @@
|
||||
export const relayerApiOrderbookChannelSubscribeSchema = {
|
||||
id: '/RelayerApiOrderbookChannelSubscribe',
|
||||
type: 'object',
|
||||
properties: {
|
||||
type: {enum: ['subscribe']},
|
||||
channel: {enum: ['orderbook']},
|
||||
payload: {$ref: '/RelayerApiOrderbookChannelSubscribePayload'},
|
||||
},
|
||||
required: ['type', 'channel', 'payload'],
|
||||
};
|
||||
|
||||
export const relayerApiOrderbookChannelSubscribePayload = {
|
||||
id: '/RelayerApiOrderbookChannelSubscribePayload',
|
||||
type: 'object',
|
||||
properties: {
|
||||
baseTokenAddress: {$ref: '/Address'},
|
||||
quoteTokenAddress: {$ref: '/Address'},
|
||||
snapshot: {type: 'boolean'},
|
||||
limit: {type: 'number'},
|
||||
},
|
||||
required: ['baseTokenAddress', 'quoteTokenAddress'],
|
||||
};
|
@ -0,0 +1,21 @@
|
||||
export const relayerApiOrderbookChannelSnapshotSchema = {
|
||||
id: '/RelayerApiOrderbookChannelSnapshot',
|
||||
type: 'object',
|
||||
properties: {
|
||||
type: {enum: ['snapshot']},
|
||||
channel: {enum: ['orderbook']},
|
||||
channelId: {type: 'number'},
|
||||
payload: {$ref: '/RelayerApiOrderbookChannelSnapshotPayload'},
|
||||
},
|
||||
required: ['type', 'channel', 'channelId', 'payload'],
|
||||
};
|
||||
|
||||
export const relayerApiOrderbookChannelSnapshotPayload = {
|
||||
id: '/RelayerApiOrderbookChannelSnapshotPayload',
|
||||
type: 'object',
|
||||
properties: {
|
||||
bids: {$ref: '/signedOrdersSchema'},
|
||||
asks: {$ref: '/signedOrdersSchema'},
|
||||
},
|
||||
required: ['bids', 'asks'],
|
||||
};
|
@ -0,0 +1,11 @@
|
||||
export const relayerApiOrderbookChannelUpdateSchema = {
|
||||
id: '/RelayerApiOrderbookChannelUpdate',
|
||||
type: 'object',
|
||||
properties: {
|
||||
type: {enum: ['update']},
|
||||
channel: {enum: ['orderbook']},
|
||||
channelId: {type: 'number'},
|
||||
payload: {$ref: '/SignedOrder'},
|
||||
},
|
||||
required: ['type', 'channel', 'channelId', 'payload'],
|
||||
};
|
@ -0,0 +1,9 @@
|
||||
export const relayerApiOrderBookResponseSchema = {
|
||||
id: '/RelayerApiOrderBookResponse',
|
||||
type: 'object',
|
||||
properties: {
|
||||
bids: {$ref: '/signedOrdersSchema'},
|
||||
asks: {$ref: '/signedOrdersSchema'},
|
||||
},
|
||||
required: ['bids', 'asks'],
|
||||
};
|
@ -0,0 +1,24 @@
|
||||
export const relayerApiTokenPairsResponseSchema = {
|
||||
id: '/RelayerApiTokenPairsResponse',
|
||||
type: 'array',
|
||||
items: {
|
||||
properties: {
|
||||
tokenA: {$ref: '/RelayerApiTokenTradeInfo'},
|
||||
tokenB: {$ref: '/RelayerApiTokenTradeInfo'},
|
||||
},
|
||||
required: ['tokenA', 'tokenB'],
|
||||
type: 'object',
|
||||
},
|
||||
};
|
||||
|
||||
export const relayerApiTokenTradeInfoSchema = {
|
||||
id: '/RelayerApiTokenTradeInfo',
|
||||
type: 'object',
|
||||
properties: {
|
||||
address: {$ref: '/Address'},
|
||||
minAmount: {$ref: '/Number'},
|
||||
maxAmount: {$ref: '/Number'},
|
||||
precision: {type: 'number'},
|
||||
},
|
||||
required: ['address'],
|
||||
};
|
5
packages/json-schemas/schemas/signed_orders_schema.ts
Normal file
5
packages/json-schemas/schemas/signed_orders_schema.ts
Normal file
@ -0,0 +1,5 @@
|
||||
export const signedOrdersSchema = {
|
||||
id: '/signedOrdersSchema',
|
||||
type: 'array',
|
||||
items: {$ref: '/SignedOrder'},
|
||||
};
|
20
packages/json-schemas/schemas/subscription_opts_schema.ts
Normal file
20
packages/json-schemas/schemas/subscription_opts_schema.ts
Normal file
@ -0,0 +1,20 @@
|
||||
export const blockParamSchema = {
|
||||
id: '/BlockParam',
|
||||
oneOf: [
|
||||
{
|
||||
type: 'number',
|
||||
},
|
||||
{
|
||||
enum: ['latest', 'earliest', 'pending'],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
export const subscriptionOptsSchema = {
|
||||
id: '/SubscriptionOpts',
|
||||
properties: {
|
||||
fromBlock: {$ref: '/BlockParam'},
|
||||
toBlock: {$ref: '/BlockParam'},
|
||||
},
|
||||
type: 'object',
|
||||
};
|
11
packages/json-schemas/schemas/token_schema.ts
Normal file
11
packages/json-schemas/schemas/token_schema.ts
Normal file
@ -0,0 +1,11 @@
|
||||
export const tokenSchema = {
|
||||
id: '/Token',
|
||||
properties: {
|
||||
name: {type: 'string'},
|
||||
symbol: {type: 'string'},
|
||||
decimals: {type: 'number'},
|
||||
address: {$ref: '/Address'},
|
||||
},
|
||||
required: ['name', 'symbol', 'decimals', 'address'],
|
||||
type: 'object',
|
||||
};
|
42
packages/json-schemas/schemas/tx_data_schema.ts
Normal file
42
packages/json-schemas/schemas/tx_data_schema.ts
Normal file
@ -0,0 +1,42 @@
|
||||
export const jsNumber = {
|
||||
id: '/JsNumber',
|
||||
type: 'number',
|
||||
minimum: 0,
|
||||
};
|
||||
|
||||
export const txDataSchema = {
|
||||
id: '/TxData',
|
||||
properties: {
|
||||
from: {$ref: '/Address'},
|
||||
to: {$ref: '/Address'},
|
||||
value: {
|
||||
oneOf: [
|
||||
{$ref: '/Number'},
|
||||
{$ref: '/JsNumber'},
|
||||
],
|
||||
},
|
||||
gas: {
|
||||
oneOf: [
|
||||
{$ref: '/Number'},
|
||||
{$ref: '/JsNumber'},
|
||||
],
|
||||
},
|
||||
gasPrice: {
|
||||
oneOf: [
|
||||
{$ref: '/Number'},
|
||||
{$ref: '/JsNumber'},
|
||||
],
|
||||
},
|
||||
data: {
|
||||
type: 'string',
|
||||
pattern: '^0x[0-9a-f]*$',
|
||||
},
|
||||
nonce: {
|
||||
type: 'number',
|
||||
minimum: 0,
|
||||
},
|
||||
},
|
||||
required: ['from'],
|
||||
type: 'object',
|
||||
additionalProperties: false,
|
||||
};
|
7
packages/json-schemas/src/globals.d.ts
vendored
Normal file
7
packages/json-schemas/src/globals.d.ts
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
declare module 'dirty-chai';
|
||||
|
||||
// es6-promisify declarations
|
||||
declare function promisify(original: any, settings?: any): ((...arg: any[]) => Promise<any>);
|
||||
declare module 'es6-promisify' {
|
||||
export = promisify;
|
||||
}
|
4
packages/json-schemas/src/index.ts
Normal file
4
packages/json-schemas/src/index.ts
Normal file
@ -0,0 +1,4 @@
|
||||
export {ValidatorResult, Schema} from 'jsonschema';
|
||||
|
||||
export {SchemaValidator} from './schema_validator';
|
||||
export {schemas} from './schemas';
|
28
packages/json-schemas/src/schema_validator.ts
Normal file
28
packages/json-schemas/src/schema_validator.ts
Normal file
@ -0,0 +1,28 @@
|
||||
import values = require('lodash.values');
|
||||
import {Validator, ValidatorResult, Schema} from 'jsonschema';
|
||||
import {schemas} from './schemas';
|
||||
|
||||
export class SchemaValidator {
|
||||
private validator: Validator;
|
||||
constructor() {
|
||||
this.validator = new Validator();
|
||||
for (const schema of values(schemas)) {
|
||||
this.validator.addSchema(schema, schema.id);
|
||||
}
|
||||
}
|
||||
public addSchema(schema: Schema) {
|
||||
this.validator.addSchema(schema, schema.id);
|
||||
}
|
||||
// In order to validate a complex JS object using jsonschema, we must replace any complex
|
||||
// sub-types (e.g BigNumber) with a simpler string representation. Since BigNumber and other
|
||||
// complex types implement the `toString` method, we can stringify the object and
|
||||
// then parse it. The resultant object can then be checked using jsonschema.
|
||||
public validate(instance: any, schema: Schema): ValidatorResult {
|
||||
const jsonSchemaCompatibleObject = JSON.parse(JSON.stringify(instance));
|
||||
return this.validator.validate(jsonSchemaCompatibleObject, schema);
|
||||
}
|
||||
public isValid(instance: any, schema: Schema): boolean {
|
||||
const isValid = this.validate(instance, schema).errors.length === 0;
|
||||
return isValid;
|
||||
}
|
||||
}
|
99
packages/json-schemas/src/schemas.ts
Normal file
99
packages/json-schemas/src/schemas.ts
Normal file
@ -0,0 +1,99 @@
|
||||
import {
|
||||
numberSchema,
|
||||
addressSchema,
|
||||
} from '../schemas/basic_type_schemas';
|
||||
import {
|
||||
ecSignatureSchema,
|
||||
ecSignatureParameterSchema,
|
||||
} from '../schemas/ec_signature_schema';
|
||||
import {
|
||||
indexFilterValuesSchema,
|
||||
} from '../schemas/index_filter_values_schema';
|
||||
import {
|
||||
orderCancellationRequestsSchema,
|
||||
} from '../schemas/order_cancel_schema';
|
||||
import {
|
||||
orderFillOrKillRequestsSchema,
|
||||
} from '../schemas/order_fill_or_kill_requests_schema';
|
||||
import {
|
||||
orderFillRequestsSchema,
|
||||
} from '../schemas/order_fill_requests_schema';
|
||||
import {
|
||||
orderHashSchema,
|
||||
} from '../schemas/order_hash_schema';
|
||||
import {
|
||||
orderSchema,
|
||||
signedOrderSchema,
|
||||
} from '../schemas/order_schemas';
|
||||
import {
|
||||
blockParamSchema,
|
||||
subscriptionOptsSchema,
|
||||
} from '../schemas/subscription_opts_schema';
|
||||
import {
|
||||
tokenSchema,
|
||||
} from '../schemas/token_schema';
|
||||
import {
|
||||
signedOrdersSchema,
|
||||
} from '../schemas/signed_orders_schema';
|
||||
import {
|
||||
relayerApiErrorResponseSchema,
|
||||
} from '../schemas/relayer_api_error_response_schema';
|
||||
import {
|
||||
relayerApiFeesResponseSchema,
|
||||
} from '../schemas/relayer_api_fees_response_schema';
|
||||
import {
|
||||
relayerApiFeesPayloadSchema,
|
||||
} from '../schemas/relayer_api_fees_payload_schema';
|
||||
import {
|
||||
relayerApiOrderBookResponseSchema,
|
||||
} from '../schemas/relayer_api_orderbook_response_schema';
|
||||
import {
|
||||
relayerApiTokenPairsResponseSchema,
|
||||
relayerApiTokenTradeInfoSchema,
|
||||
} from '../schemas/relayer_api_token_pairs_response_schema';
|
||||
import {
|
||||
jsNumber,
|
||||
txDataSchema,
|
||||
} from '../schemas/tx_data_schema';
|
||||
import {
|
||||
relayerApiOrderbookChannelSubscribeSchema,
|
||||
relayerApiOrderbookChannelSubscribePayload,
|
||||
} from '../schemas/relayer_api_orberbook_channel_subscribe_schema';
|
||||
import {
|
||||
relayerApiOrderbookChannelUpdateSchema,
|
||||
} from '../schemas/relayer_api_orderbook_channel_update_response_schema';
|
||||
import {
|
||||
relayerApiOrderbookChannelSnapshotSchema,
|
||||
relayerApiOrderbookChannelSnapshotPayload,
|
||||
} from '../schemas/relayer_api_orderbook_channel_snapshot_schema';
|
||||
|
||||
export const schemas = {
|
||||
numberSchema,
|
||||
addressSchema,
|
||||
ecSignatureSchema,
|
||||
ecSignatureParameterSchema,
|
||||
indexFilterValuesSchema,
|
||||
orderCancellationRequestsSchema,
|
||||
orderFillOrKillRequestsSchema,
|
||||
orderFillRequestsSchema,
|
||||
orderHashSchema,
|
||||
orderSchema,
|
||||
signedOrderSchema,
|
||||
signedOrdersSchema,
|
||||
blockParamSchema,
|
||||
subscriptionOptsSchema,
|
||||
tokenSchema,
|
||||
jsNumber,
|
||||
txDataSchema,
|
||||
relayerApiErrorResponseSchema,
|
||||
relayerApiFeesPayloadSchema,
|
||||
relayerApiFeesResponseSchema,
|
||||
relayerApiOrderBookResponseSchema,
|
||||
relayerApiTokenPairsResponseSchema,
|
||||
relayerApiTokenTradeInfoSchema,
|
||||
relayerApiOrderbookChannelSubscribeSchema,
|
||||
relayerApiOrderbookChannelSubscribePayload,
|
||||
relayerApiOrderbookChannelUpdateSchema,
|
||||
relayerApiOrderbookChannelSnapshotSchema,
|
||||
relayerApiOrderbookChannelSnapshotPayload,
|
||||
};
|
972
packages/json-schemas/test/schema_test.ts
Normal file
972
packages/json-schemas/test/schema_test.ts
Normal file
@ -0,0 +1,972 @@
|
||||
import 'mocha';
|
||||
import forEach = require('lodash.foreach');
|
||||
import * as dirtyChai from 'dirty-chai';
|
||||
import * as chai from 'chai';
|
||||
import BigNumber from 'bignumber.js';
|
||||
import promisify = require('es6-promisify');
|
||||
import {SchemaValidator, schemas} from '../src/index';
|
||||
|
||||
chai.config.includeStack = true;
|
||||
chai.use(dirtyChai);
|
||||
const expect = chai.expect;
|
||||
const NULL_ADDRESS = '0x0000000000000000000000000000000000000000';
|
||||
const {
|
||||
numberSchema,
|
||||
addressSchema,
|
||||
ecSignatureSchema,
|
||||
ecSignatureParameterSchema,
|
||||
indexFilterValuesSchema,
|
||||
orderCancellationRequestsSchema,
|
||||
orderFillOrKillRequestsSchema,
|
||||
orderFillRequestsSchema,
|
||||
orderHashSchema,
|
||||
orderSchema,
|
||||
signedOrderSchema,
|
||||
signedOrdersSchema,
|
||||
blockParamSchema,
|
||||
subscriptionOptsSchema,
|
||||
tokenSchema,
|
||||
jsNumber,
|
||||
txDataSchema,
|
||||
relayerApiErrorResponseSchema,
|
||||
relayerApiOrderBookResponseSchema,
|
||||
relayerApiTokenPairsResponseSchema,
|
||||
relayerApiFeesPayloadSchema,
|
||||
relayerApiFeesResponseSchema,
|
||||
relayerApiOrderbookChannelSubscribeSchema,
|
||||
relayerApiOrderbookChannelUpdateSchema,
|
||||
relayerApiOrderbookChannelSnapshotSchema,
|
||||
} = schemas;
|
||||
|
||||
describe('Schema', () => {
|
||||
const validator = new SchemaValidator();
|
||||
const validateAgainstSchema = (testCases: any[], schema: any, shouldFail = false) => {
|
||||
forEach(testCases, (testCase: any) => {
|
||||
const validationResult = validator.validate(testCase, schema);
|
||||
const hasErrors = validationResult.errors.length !== 0;
|
||||
if (shouldFail) {
|
||||
if (!hasErrors) {
|
||||
throw new Error(
|
||||
`Expected testCase: ${JSON.stringify(testCase, null, '\t')} to fail and it didn't.`,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
if (hasErrors) {
|
||||
throw new Error(JSON.stringify(validationResult.errors, null, '\t'));
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
describe('#numberSchema', () => {
|
||||
it('should validate valid numbers', () => {
|
||||
const testCases = ['42', '0', '1.3', '0.2', '00.00'];
|
||||
validateAgainstSchema(testCases, numberSchema);
|
||||
});
|
||||
it('should fail for invalid numbers', () => {
|
||||
const testCases = ['.3', '1.', 'abacaba', 'и', '1..0'];
|
||||
const shouldFail = true;
|
||||
validateAgainstSchema(testCases, numberSchema, shouldFail);
|
||||
});
|
||||
});
|
||||
describe('#addressSchema', () => {
|
||||
it('should validate valid addresses', () => {
|
||||
const testCases = ['0x8b0292b11a196601ed2ce54b665cafeca0347d42', NULL_ADDRESS];
|
||||
validateAgainstSchema(testCases, addressSchema);
|
||||
});
|
||||
it('should fail for invalid addresses', () => {
|
||||
const testCases = [
|
||||
'0x',
|
||||
'0',
|
||||
'0x00',
|
||||
'0xzzzzzzB11a196601eD2ce54B665CaFEca0347D42',
|
||||
'0x8b0292B11a196601eD2ce54B665CaFEca0347D42',
|
||||
];
|
||||
const shouldFail = true;
|
||||
validateAgainstSchema(testCases, addressSchema, shouldFail);
|
||||
});
|
||||
});
|
||||
describe('#ecSignatureParameterSchema', () => {
|
||||
it('should validate valid parameters', () => {
|
||||
const testCases = [
|
||||
'0x61a3ed31b43c8780e905a260a35faefcc527be7516aa11c0256729b5b351bc33',
|
||||
'0X40349190569279751135161d22529dc25add4f6069af05be04cacbda2ace2254',
|
||||
];
|
||||
validateAgainstSchema(testCases, ecSignatureParameterSchema);
|
||||
});
|
||||
it('should fail for invalid parameters', () => {
|
||||
const testCases = [
|
||||
'0x61a3ed31b43c8780e905a260a35faefcc527be7516aa11c0256729b5b351bc3', // shorter
|
||||
'0xzzzz9190569279751135161d22529dc25add4f6069af05be04cacbda2ace2254', // invalid characters
|
||||
'40349190569279751135161d22529dc25add4f6069af05be04cacbda2ace2254', // no 0x
|
||||
];
|
||||
const shouldFail = true;
|
||||
validateAgainstSchema(testCases, ecSignatureParameterSchema, shouldFail);
|
||||
});
|
||||
});
|
||||
describe('#ecSignatureSchema', () => {
|
||||
it('should validate valid signature', () => {
|
||||
const signature = {
|
||||
v: 27,
|
||||
r: '0x61a3ed31b43c8780e905a260a35faefcc527be7516aa11c0256729b5b351bc33',
|
||||
s: '0x40349190569279751135161d22529dc25add4f6069af05be04cacbda2ace2254',
|
||||
};
|
||||
const testCases = [
|
||||
signature,
|
||||
{
|
||||
...signature,
|
||||
v: 28,
|
||||
},
|
||||
];
|
||||
validateAgainstSchema(testCases, ecSignatureSchema);
|
||||
});
|
||||
it('should fail for invalid signature', () => {
|
||||
const v = 27;
|
||||
const r = '0x61a3ed31b43c8780e905a260a35faefcc527be7516aa11c0256729b5b351bc33';
|
||||
const s = '0x40349190569279751135161d22529dc25add4f6069af05be04cacbda2ace2254';
|
||||
const testCases = [
|
||||
{},
|
||||
{v},
|
||||
{r, s, v: 31},
|
||||
];
|
||||
const shouldFail = true;
|
||||
validateAgainstSchema(testCases, ecSignatureSchema, shouldFail);
|
||||
});
|
||||
});
|
||||
describe('#orderHashSchema', () => {
|
||||
it('should validate valid order hash', () => {
|
||||
const testCases = [
|
||||
'0x61a3ed31B43c8780e905a260a35faefEc527be7516aa11c0256729b5b351bc33',
|
||||
'0x40349190569279751135161d22529dc25add4f6069af05be04cacbda2ace2254',
|
||||
];
|
||||
validateAgainstSchema(testCases, orderHashSchema);
|
||||
});
|
||||
it('should fail for invalid order hash', () => {
|
||||
const testCases = [
|
||||
{},
|
||||
'0x',
|
||||
'0x8b0292B11a196601eD2ce54B665CaFEca0347D42',
|
||||
'61a3ed31B43c8780e905a260a35faefEc527be7516aa11c0256729b5b351bc33',
|
||||
];
|
||||
const shouldFail = true;
|
||||
validateAgainstSchema(testCases, orderHashSchema, shouldFail);
|
||||
});
|
||||
});
|
||||
describe('#blockParamSchema', () => {
|
||||
it('should validate valid block param', () => {
|
||||
const testCases = [
|
||||
42,
|
||||
'latest',
|
||||
'pending',
|
||||
'earliest',
|
||||
];
|
||||
validateAgainstSchema(testCases, blockParamSchema);
|
||||
});
|
||||
it('should fail for invalid block param', () => {
|
||||
const testCases = [
|
||||
{},
|
||||
'42',
|
||||
'pemding',
|
||||
];
|
||||
const shouldFail = true;
|
||||
validateAgainstSchema(testCases, blockParamSchema, shouldFail);
|
||||
});
|
||||
});
|
||||
describe('#subscriptionOptsSchema', () => {
|
||||
it('should validate valid subscription opts', () => {
|
||||
const testCases = [
|
||||
{fromBlock: 42, toBlock: 'latest'},
|
||||
{fromBlock: 42},
|
||||
{},
|
||||
];
|
||||
validateAgainstSchema(testCases, subscriptionOptsSchema);
|
||||
});
|
||||
it('should fail for invalid subscription opts', () => {
|
||||
const testCases = [
|
||||
{fromBlock: '42'},
|
||||
];
|
||||
const shouldFail = true;
|
||||
validateAgainstSchema(testCases, subscriptionOptsSchema, shouldFail);
|
||||
});
|
||||
});
|
||||
describe('#tokenSchema', () => {
|
||||
const token = {
|
||||
name: 'Zero Ex',
|
||||
symbol: 'ZRX',
|
||||
decimals: 100500,
|
||||
address: '0x8b0292b11a196601ed2ce54b665cafeca0347d42',
|
||||
url: 'https://0xproject.com',
|
||||
};
|
||||
it('should validate valid token', () => {
|
||||
const testCases = [
|
||||
token,
|
||||
];
|
||||
validateAgainstSchema(testCases, tokenSchema);
|
||||
});
|
||||
it('should fail for invalid token', () => {
|
||||
const testCases = [
|
||||
{
|
||||
...token,
|
||||
address: null,
|
||||
},
|
||||
{
|
||||
...token,
|
||||
decimals: undefined,
|
||||
},
|
||||
[],
|
||||
4,
|
||||
];
|
||||
const shouldFail = true;
|
||||
validateAgainstSchema(testCases, tokenSchema, shouldFail);
|
||||
});
|
||||
});
|
||||
describe('order including schemas', () => {
|
||||
const order = {
|
||||
maker: NULL_ADDRESS,
|
||||
taker: NULL_ADDRESS,
|
||||
makerFee: '1',
|
||||
takerFee: '2',
|
||||
makerTokenAmount: '1',
|
||||
takerTokenAmount: '2',
|
||||
makerTokenAddress: NULL_ADDRESS,
|
||||
takerTokenAddress: NULL_ADDRESS,
|
||||
salt: '67006738228878699843088602623665307406148487219438534730168799356281242528500',
|
||||
feeRecipient: NULL_ADDRESS,
|
||||
exchangeContractAddress: NULL_ADDRESS,
|
||||
expirationUnixTimestampSec: '42',
|
||||
};
|
||||
describe('#orderSchema', () => {
|
||||
it('should validate valid order', () => {
|
||||
const testCases = [
|
||||
order,
|
||||
];
|
||||
validateAgainstSchema(testCases, orderSchema);
|
||||
});
|
||||
it('should fail for invalid order', () => {
|
||||
const testCases = [
|
||||
{
|
||||
...order,
|
||||
salt: undefined,
|
||||
},
|
||||
{
|
||||
...order,
|
||||
salt: 'salt',
|
||||
},
|
||||
'order',
|
||||
];
|
||||
const shouldFail = true;
|
||||
validateAgainstSchema(testCases, orderSchema, shouldFail);
|
||||
});
|
||||
});
|
||||
describe('signed order including schemas', () => {
|
||||
const signedOrder = {
|
||||
...order,
|
||||
ecSignature: {
|
||||
v: 27,
|
||||
r: '0x61a3ed31b43c8780e905a260a35faefcc527be7516aa11c0256729b5b351bc33',
|
||||
s: '0x40349190569279751135161d22529dc25add4f6069af05be04cacbda2ace2254',
|
||||
},
|
||||
};
|
||||
describe('#signedOrdersSchema', () => {
|
||||
it('should validate valid signed orders', () => {
|
||||
const testCases = [
|
||||
[signedOrder],
|
||||
[],
|
||||
];
|
||||
validateAgainstSchema(testCases, signedOrdersSchema);
|
||||
});
|
||||
it('should fail for invalid signed orders', () => {
|
||||
const testCases = [
|
||||
[
|
||||
signedOrder,
|
||||
1,
|
||||
],
|
||||
];
|
||||
const shouldFail = true;
|
||||
validateAgainstSchema(testCases, signedOrdersSchema, shouldFail);
|
||||
});
|
||||
});
|
||||
describe('#signedOrderSchema', () => {
|
||||
it('should validate valid signed order', () => {
|
||||
const testCases = [
|
||||
signedOrder,
|
||||
];
|
||||
validateAgainstSchema(testCases, signedOrderSchema);
|
||||
});
|
||||
it('should fail for invalid signed order', () => {
|
||||
const testCases = [
|
||||
{
|
||||
...signedOrder,
|
||||
ecSignature: undefined,
|
||||
},
|
||||
];
|
||||
const shouldFail = true;
|
||||
validateAgainstSchema(testCases, signedOrderSchema, shouldFail);
|
||||
});
|
||||
});
|
||||
describe('#orderFillOrKillRequestsSchema', () => {
|
||||
const orderFillOrKillRequests = [
|
||||
{
|
||||
signedOrder,
|
||||
fillTakerAmount: '5',
|
||||
},
|
||||
];
|
||||
it('should validate valid order fill or kill requests', () => {
|
||||
const testCases = [
|
||||
orderFillOrKillRequests,
|
||||
];
|
||||
validateAgainstSchema(testCases, orderFillOrKillRequestsSchema);
|
||||
});
|
||||
it('should fail for invalid order fill or kill requests', () => {
|
||||
const testCases = [
|
||||
[
|
||||
{
|
||||
...orderFillOrKillRequests[0],
|
||||
fillTakerAmount: undefined,
|
||||
},
|
||||
],
|
||||
];
|
||||
const shouldFail = true;
|
||||
validateAgainstSchema(testCases, orderFillOrKillRequestsSchema, shouldFail);
|
||||
});
|
||||
});
|
||||
describe('#orderCancellationRequestsSchema', () => {
|
||||
const orderCancellationRequests = [
|
||||
{
|
||||
order,
|
||||
takerTokenCancelAmount: '5',
|
||||
},
|
||||
];
|
||||
it('should validate valid order cancellation requests', () => {
|
||||
const testCases = [
|
||||
orderCancellationRequests,
|
||||
];
|
||||
validateAgainstSchema(testCases, orderCancellationRequestsSchema);
|
||||
});
|
||||
it('should fail for invalid order cancellation requests', () => {
|
||||
const testCases = [
|
||||
[
|
||||
{
|
||||
...orderCancellationRequests[0],
|
||||
takerTokenCancelAmount: undefined,
|
||||
},
|
||||
],
|
||||
];
|
||||
const shouldFail = true;
|
||||
validateAgainstSchema(testCases, orderCancellationRequestsSchema, shouldFail);
|
||||
});
|
||||
});
|
||||
describe('#orderFillRequestsSchema', () => {
|
||||
const orderFillRequests = [
|
||||
{
|
||||
signedOrder,
|
||||
takerTokenFillAmount: '5',
|
||||
},
|
||||
];
|
||||
it('should validate valid order fill requests', () => {
|
||||
const testCases = [
|
||||
orderFillRequests,
|
||||
];
|
||||
validateAgainstSchema(testCases, orderFillRequestsSchema);
|
||||
});
|
||||
it('should fail for invalid order fill requests', () => {
|
||||
const testCases = [
|
||||
[
|
||||
{
|
||||
...orderFillRequests[0],
|
||||
takerTokenFillAmount: undefined,
|
||||
},
|
||||
],
|
||||
];
|
||||
const shouldFail = true;
|
||||
validateAgainstSchema(testCases, orderFillRequestsSchema, shouldFail);
|
||||
});
|
||||
});
|
||||
describe('#relayerApiOrderBookResponseSchema', () => {
|
||||
it('should validate valid order book responses', () => {
|
||||
const testCases = [
|
||||
{
|
||||
bids: [],
|
||||
asks: [],
|
||||
},
|
||||
{
|
||||
bids: [signedOrder, signedOrder],
|
||||
asks: [],
|
||||
},
|
||||
{
|
||||
bids: [],
|
||||
asks: [signedOrder, signedOrder],
|
||||
},
|
||||
{
|
||||
bids: [signedOrder],
|
||||
asks: [signedOrder, signedOrder],
|
||||
},
|
||||
];
|
||||
validateAgainstSchema(testCases, relayerApiOrderBookResponseSchema);
|
||||
});
|
||||
it('should fail for invalid order fill requests', () => {
|
||||
const testCases = [
|
||||
{},
|
||||
{
|
||||
bids: [signedOrder, signedOrder],
|
||||
},
|
||||
{
|
||||
asks: [signedOrder, signedOrder],
|
||||
},
|
||||
{
|
||||
bids: signedOrder,
|
||||
asks: [signedOrder, signedOrder],
|
||||
},
|
||||
{
|
||||
bids: [signedOrder],
|
||||
asks: signedOrder,
|
||||
},
|
||||
];
|
||||
const shouldFail = true;
|
||||
validateAgainstSchema(testCases, relayerApiOrderBookResponseSchema, shouldFail);
|
||||
});
|
||||
});
|
||||
describe('#relayerApiOrderbookChannelSubscribeSchema', () => {
|
||||
it('should validate valid orderbook channel websocket subscribe message', () => {
|
||||
const testCases = [
|
||||
{
|
||||
type: 'subscribe',
|
||||
channel: 'orderbook',
|
||||
payload: {
|
||||
baseTokenAddress: '0x323b5d4c32345ced77393b3530b1eed0f346429d',
|
||||
quoteTokenAddress: '0x323b5d4c32345ced77393b3530b1eed0f346429d',
|
||||
snapshot: true,
|
||||
limit: 100,
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'subscribe',
|
||||
channel: 'orderbook',
|
||||
payload: {
|
||||
baseTokenAddress: '0x323b5d4c32345ced77393b3530b1eed0f346429d',
|
||||
quoteTokenAddress: '0x323b5d4c32345ced77393b3530b1eed0f346429d',
|
||||
},
|
||||
},
|
||||
];
|
||||
validateAgainstSchema(testCases, relayerApiOrderbookChannelSubscribeSchema);
|
||||
});
|
||||
it('should fail for invalid orderbook channel websocket subscribe message', () => {
|
||||
const checksummedAddress = '0xA2b31daCf30a9C50ca473337c01d8A201ae33e32';
|
||||
const testCases = [
|
||||
{
|
||||
type: 'foo',
|
||||
channel: 'orderbook',
|
||||
payload: {
|
||||
baseTokenAddress: '0x323b5d4c32345ced77393b3530b1eed0f346429d',
|
||||
quoteTokenAddress: '0x323b5d4c32345ced77393b3530b1eed0f346429d',
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'subscribe',
|
||||
channel: 'bar',
|
||||
payload: {
|
||||
baseTokenAddress: '0x323b5d4c32345ced77393b3530b1eed0f346429d',
|
||||
quoteTokenAddress: '0x323b5d4c32345ced77393b3530b1eed0f346429d',
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'subscribe',
|
||||
channel: 'orderbook',
|
||||
payload: {
|
||||
baseTokenAddress: checksummedAddress,
|
||||
quoteTokenAddress: '0x323b5d4c32345ced77393b3530b1eed0f346429d',
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'subscribe',
|
||||
channel: 'orderbook',
|
||||
payload: {
|
||||
baseTokenAddress: '0x323b5d4c32345ced77393b3530b1eed0f346429d',
|
||||
quoteTokenAddress: checksummedAddress,
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'subscribe',
|
||||
channel: 'orderbook',
|
||||
payload: {
|
||||
quoteTokenAddress: '0x323b5d4c32345ced77393b3530b1eed0f346429d',
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'subscribe',
|
||||
channel: 'orderbook',
|
||||
payload: {
|
||||
baseTokenAddress: '0x323b5d4c32345ced77393b3530b1eed0f346429d',
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'subscribe',
|
||||
channel: 'orderbook',
|
||||
payload: {
|
||||
baseTokenAddress: '0x323b5d4c32345ced77393b3530b1eed0f346429d',
|
||||
quoteTokenAddress: '0x323b5d4c32345ced77393b3530b1eed0f346429d',
|
||||
snapshot: 'true',
|
||||
limit: 100,
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'subscribe',
|
||||
channel: 'orderbook',
|
||||
payload: {
|
||||
baseTokenAddress: '0x323b5d4c32345ced77393b3530b1eed0f346429d',
|
||||
quoteTokenAddress: '0x323b5d4c32345ced77393b3530b1eed0f346429d',
|
||||
snapshot: true,
|
||||
limit: '100',
|
||||
},
|
||||
},
|
||||
];
|
||||
const shouldFail = true;
|
||||
validateAgainstSchema(testCases, relayerApiOrderbookChannelSubscribeSchema, shouldFail);
|
||||
});
|
||||
});
|
||||
describe('#relayerApiOrderbookChannelSnapshotSchema', () => {
|
||||
it('should validate valid orderbook channel websocket snapshot message', () => {
|
||||
const testCases = [
|
||||
{
|
||||
type: 'snapshot',
|
||||
channel: 'orderbook',
|
||||
channelId: 2,
|
||||
payload: {
|
||||
bids: [],
|
||||
asks: [],
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'snapshot',
|
||||
channel: 'orderbook',
|
||||
channelId: 2,
|
||||
payload: {
|
||||
bids: [
|
||||
signedOrder,
|
||||
],
|
||||
asks: [
|
||||
signedOrder,
|
||||
],
|
||||
},
|
||||
},
|
||||
];
|
||||
validateAgainstSchema(testCases, relayerApiOrderbookChannelSnapshotSchema);
|
||||
});
|
||||
it('should fail for invalid orderbook channel websocket snapshot message', () => {
|
||||
const testCases = [
|
||||
{
|
||||
type: 'foo',
|
||||
channel: 'orderbook',
|
||||
channelId: 2,
|
||||
payload: {
|
||||
bids: [
|
||||
signedOrder,
|
||||
],
|
||||
asks: [
|
||||
signedOrder,
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'snapshot',
|
||||
channel: 'bar',
|
||||
channelId: 2,
|
||||
payload: {
|
||||
bids: [
|
||||
signedOrder,
|
||||
],
|
||||
asks: [
|
||||
signedOrder,
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'snapshot',
|
||||
channel: 'orderbook',
|
||||
payload: {
|
||||
bids: [
|
||||
signedOrder,
|
||||
],
|
||||
asks: [
|
||||
signedOrder,
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'snapshot',
|
||||
channel: 'orderbook',
|
||||
channelId: '2',
|
||||
payload: {
|
||||
bids: [
|
||||
signedOrder,
|
||||
],
|
||||
asks: [
|
||||
signedOrder,
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'snapshot',
|
||||
channel: 'orderbook',
|
||||
channelId: 2,
|
||||
payload: {
|
||||
bids: [
|
||||
signedOrder,
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'snapshot',
|
||||
channel: 'orderbook',
|
||||
channelId: 2,
|
||||
payload: {
|
||||
asks: [
|
||||
signedOrder,
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'snapshot',
|
||||
channel: 'orderbook',
|
||||
channelId: 2,
|
||||
payload: {
|
||||
bids: [
|
||||
signedOrder,
|
||||
],
|
||||
asks: [
|
||||
{},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'snapshot',
|
||||
channel: 'orderbook',
|
||||
channelId: 2,
|
||||
payload: {
|
||||
bids: [
|
||||
{},
|
||||
],
|
||||
asks: [
|
||||
signedOrder,
|
||||
],
|
||||
},
|
||||
},
|
||||
];
|
||||
const shouldFail = true;
|
||||
validateAgainstSchema(testCases, relayerApiOrderbookChannelSnapshotSchema, shouldFail);
|
||||
});
|
||||
});
|
||||
describe('#relayerApiOrderbookChannelUpdateSchema', () => {
|
||||
it('should validate valid orderbook channel websocket update message', () => {
|
||||
const testCases = [
|
||||
{
|
||||
type: 'update',
|
||||
channel: 'orderbook',
|
||||
channelId: 2,
|
||||
payload: signedOrder,
|
||||
},
|
||||
];
|
||||
validateAgainstSchema(testCases, relayerApiOrderbookChannelUpdateSchema);
|
||||
});
|
||||
it('should fail for invalid orderbook channel websocket update message', () => {
|
||||
const testCases = [
|
||||
{
|
||||
type: 'foo',
|
||||
channel: 'orderbook',
|
||||
payload: signedOrder,
|
||||
},
|
||||
{
|
||||
type: 'update',
|
||||
channel: 'bar',
|
||||
payload: signedOrder,
|
||||
},
|
||||
{
|
||||
type: 'update',
|
||||
channel: 'orderbook',
|
||||
payload: {},
|
||||
},
|
||||
];
|
||||
const shouldFail = true;
|
||||
validateAgainstSchema(testCases, relayerApiOrderbookChannelUpdateSchema, shouldFail);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('BigNumber serialization', () => {
|
||||
it('should correctly serialize BigNumbers', () => {
|
||||
const testCases = {
|
||||
'42': '42',
|
||||
'0': '0',
|
||||
'1.3': '1.3',
|
||||
'0.2': '0.2',
|
||||
'00.00': '0',
|
||||
'.3': '0.3',
|
||||
};
|
||||
forEach(testCases, (serialized: string, input: string) => {
|
||||
expect(JSON.parse(JSON.stringify(new BigNumber(input)))).to.be.equal(serialized);
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('#relayerApiErrorResponseSchema', () => {
|
||||
it('should validate valid errorResponse', () => {
|
||||
const testCases = [
|
||||
{
|
||||
code: 102,
|
||||
reason: 'Order submission disabled',
|
||||
},
|
||||
{
|
||||
code: 101,
|
||||
reason: 'Validation failed',
|
||||
validationErrors: [
|
||||
{
|
||||
field: 'maker',
|
||||
code: 1002,
|
||||
reason: 'Invalid address',
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
validateAgainstSchema(testCases, relayerApiErrorResponseSchema);
|
||||
});
|
||||
it('should fail for invalid error responses', () => {
|
||||
const testCases = [
|
||||
{},
|
||||
{
|
||||
code: 102,
|
||||
},
|
||||
{
|
||||
code: '102',
|
||||
reason: 'Order submission disabled',
|
||||
},
|
||||
{
|
||||
reason: 'Order submission disabled',
|
||||
},
|
||||
{
|
||||
code: 101,
|
||||
reason: 'Validation failed',
|
||||
validationErrors: [
|
||||
{
|
||||
field: 'maker',
|
||||
reason: 'Invalid address',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
code: 101,
|
||||
reason: 'Validation failed',
|
||||
validationErrors: [
|
||||
{
|
||||
field: 'maker',
|
||||
code: '1002',
|
||||
reason: 'Invalid address',
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
const shouldFail = true;
|
||||
validateAgainstSchema(testCases, relayerApiErrorResponseSchema, shouldFail);
|
||||
});
|
||||
});
|
||||
describe('#relayerApiFeesPayloadSchema', () => {
|
||||
it('should validate valid fees payloads', () => {
|
||||
const testCases = [
|
||||
{
|
||||
exchangeContractAddress: '0x323b5d4c32345ced77393b3530b1eed0f346429d',
|
||||
maker: '0x323b5d4c32345ced77393b3530b1eed0f346429d',
|
||||
taker: '0x323b5d4c32345ced77393b3530b1eed0f346429d',
|
||||
makerTokenAddress: '0x323b5d4c32345ced77393b3530b1eed0f346429d',
|
||||
takerTokenAddress: '0xef7fff64389b814a946f3e92105513705ca6b990',
|
||||
makerTokenAmount: '10000000000000000000',
|
||||
takerTokenAmount: '30000000000000000000',
|
||||
expirationUnixTimestampSec: '42',
|
||||
salt: '67006738228878699843088602623665307406148487219438534730168799356281242528500',
|
||||
},
|
||||
];
|
||||
validateAgainstSchema(testCases, relayerApiFeesPayloadSchema);
|
||||
});
|
||||
it('should fail for invalid fees payloads', () => {
|
||||
const checksummedAddress = '0xA2b31daCf30a9C50ca473337c01d8A201ae33e32';
|
||||
const testCases = [
|
||||
{},
|
||||
{
|
||||
takerTokenAddress: '0xef7fff64389b814a946f3e92105513705ca6b990',
|
||||
makerTokenAmount: '10000000000000000000',
|
||||
takerTokenAmount: '30000000000000000000',
|
||||
},
|
||||
{
|
||||
taker: checksummedAddress,
|
||||
makerTokenAddress: '0x323b5d4c32345ced77393b3530b1eed0f346429d',
|
||||
takerTokenAddress: '0xef7fff64389b814a946f3e92105513705ca6b990',
|
||||
makerTokenAmount: '10000000000000000000',
|
||||
takerTokenAmount: '30000000000000000000',
|
||||
},
|
||||
{
|
||||
makerTokenAddress: '0x323b5d4c32345ced77393b3530b1eed0f346429d',
|
||||
takerTokenAddress: '0xef7fff64389b814a946f3e92105513705ca6b990',
|
||||
makerTokenAmount: 10000000000000000000,
|
||||
takerTokenAmount: 30000000000000000000,
|
||||
},
|
||||
];
|
||||
const shouldFail = true;
|
||||
validateAgainstSchema(testCases, relayerApiFeesPayloadSchema, shouldFail);
|
||||
});
|
||||
});
|
||||
describe('#relayerApiFeesResponseSchema', () => {
|
||||
it('should validate valid fees responses', () => {
|
||||
const testCases = [
|
||||
{
|
||||
makerFee: '10000000000000000',
|
||||
takerFee: '30000000000000000',
|
||||
feeRecipient: '0x323b5d4c32345ced77393b3530b1eed0f346429d',
|
||||
},
|
||||
];
|
||||
validateAgainstSchema(testCases, relayerApiFeesResponseSchema);
|
||||
});
|
||||
it('should fail for invalid fees responses', () => {
|
||||
const checksummedAddress = '0xA2b31daCf30a9C50ca473337c01d8A201ae33e32';
|
||||
const testCases = [
|
||||
{},
|
||||
{
|
||||
makerFee: 10000000000000000,
|
||||
takerFee: 30000000000000000,
|
||||
},
|
||||
{
|
||||
feeRecipient: checksummedAddress,
|
||||
takerToSpecify: checksummedAddress,
|
||||
makerFee: '10000000000000000',
|
||||
takerFee: '30000000000000000',
|
||||
},
|
||||
];
|
||||
const shouldFail = true;
|
||||
validateAgainstSchema(testCases, relayerApiFeesResponseSchema, shouldFail);
|
||||
});
|
||||
});
|
||||
describe('#relayerApiTokenPairsResponseSchema', () => {
|
||||
it('should validate valid tokenPairs response', () => {
|
||||
const testCases = [
|
||||
[],
|
||||
[
|
||||
{
|
||||
tokenA: {
|
||||
address: '0x323b5d4c32345ced77393b3530b1eed0f346429d',
|
||||
minAmount: '0',
|
||||
maxAmount: '10000000000000000000',
|
||||
precision: 5,
|
||||
},
|
||||
tokenB: {
|
||||
address: '0xef7fff64389b814a946f3e92105513705ca6b990',
|
||||
minAmount: '0',
|
||||
maxAmount: '50000000000000000000',
|
||||
precision: 5,
|
||||
},
|
||||
},
|
||||
],
|
||||
[
|
||||
{
|
||||
tokenA: {
|
||||
address: '0x323b5d4c32345ced77393b3530b1eed0f346429d',
|
||||
},
|
||||
tokenB: {
|
||||
address: '0xef7fff64389b814a946f3e92105513705ca6b990',
|
||||
},
|
||||
},
|
||||
],
|
||||
];
|
||||
validateAgainstSchema(testCases, relayerApiTokenPairsResponseSchema);
|
||||
});
|
||||
it('should fail for invalid tokenPairs responses', () => {
|
||||
const checksummedAddress = '0xA2b31daCf30a9C50ca473337c01d8A201ae33e32';
|
||||
const testCases = [
|
||||
[
|
||||
{
|
||||
tokenA: {
|
||||
address: checksummedAddress,
|
||||
},
|
||||
tokenB: {
|
||||
address: checksummedAddress,
|
||||
},
|
||||
},
|
||||
],
|
||||
[
|
||||
{
|
||||
tokenA: {
|
||||
address: '0x323b5d4c32345ced77393b3530b1eed0f346429d',
|
||||
minAmount: 0,
|
||||
maxAmount: 10000000000000000000,
|
||||
},
|
||||
tokenB: {
|
||||
address: '0xef7fff64389b814a946f3e92105513705ca6b990',
|
||||
minAmount: 0,
|
||||
maxAmount: 50000000000000000000,
|
||||
},
|
||||
},
|
||||
],
|
||||
[
|
||||
{
|
||||
tokenA: {
|
||||
address: '0x323b5d4c32345ced77393b3530b1eed0f346429d',
|
||||
precision: '5',
|
||||
},
|
||||
tokenB: {
|
||||
address: '0xef7fff64389b814a946f3e92105513705ca6b990',
|
||||
precision: '5',
|
||||
},
|
||||
},
|
||||
],
|
||||
];
|
||||
const shouldFail = true;
|
||||
validateAgainstSchema(testCases, relayerApiTokenPairsResponseSchema, shouldFail);
|
||||
});
|
||||
});
|
||||
describe('#jsNumberSchema', () => {
|
||||
it('should validate valid js number', () => {
|
||||
const testCases = [
|
||||
1,
|
||||
42,
|
||||
];
|
||||
validateAgainstSchema(testCases, jsNumber);
|
||||
});
|
||||
it('should fail for invalid js number', () => {
|
||||
const testCases = [
|
||||
NaN,
|
||||
-1,
|
||||
new BigNumber(1),
|
||||
];
|
||||
const shouldFail = true;
|
||||
validateAgainstSchema(testCases, jsNumber, shouldFail);
|
||||
});
|
||||
});
|
||||
describe('#txDataSchema', () => {
|
||||
it('should validate valid txData', () => {
|
||||
const testCases = [
|
||||
{
|
||||
from: NULL_ADDRESS,
|
||||
},
|
||||
{
|
||||
from: NULL_ADDRESS,
|
||||
gas: new BigNumber(42),
|
||||
},
|
||||
{
|
||||
from: NULL_ADDRESS,
|
||||
gas: 42,
|
||||
},
|
||||
];
|
||||
validateAgainstSchema(testCases, txDataSchema);
|
||||
});
|
||||
it('should fail for invalid txData', () => {
|
||||
const testCases = [
|
||||
{
|
||||
gas: new BigNumber(42),
|
||||
},
|
||||
{
|
||||
from: NULL_ADDRESS,
|
||||
unknownProp: 'here',
|
||||
},
|
||||
{},
|
||||
[],
|
||||
new BigNumber(1),
|
||||
];
|
||||
const shouldFail = true;
|
||||
validateAgainstSchema(testCases, txDataSchema, shouldFail);
|
||||
});
|
||||
});
|
||||
});
|
17
packages/json-schemas/tsconfig.json
Normal file
17
packages/json-schemas/tsconfig.json
Normal file
@ -0,0 +1,17 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"module": "commonjs",
|
||||
"target": "es5",
|
||||
"lib": [ "es2017", "dom"],
|
||||
"outDir": "lib",
|
||||
"sourceMap": true,
|
||||
"declaration": true,
|
||||
"noImplicitAny": true,
|
||||
"strictNullChecks": true
|
||||
},
|
||||
"include": [
|
||||
"./src/**/*",
|
||||
"./test/**/*",
|
||||
"../../node_modules/chai-typescript-typings/index.d.ts"
|
||||
]
|
||||
}
|
5
packages/json-schemas/tslint.json
Normal file
5
packages/json-schemas/tslint.json
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"extends": [
|
||||
"tslint-config-0xproject"
|
||||
]
|
||||
}
|
27
yarn.lock
27
yarn.lock
@ -2,13 +2,6 @@
|
||||
# yarn lockfile v1
|
||||
|
||||
|
||||
"0x-json-schemas@^0.6.1", "0x-json-schemas@^0.6.5":
|
||||
version "0.6.6"
|
||||
resolved "https://registry.yarnpkg.com/0x-json-schemas/-/0x-json-schemas-0.6.6.tgz#3852e639245474a14daa2f8c454ba83ca5df8a9c"
|
||||
dependencies:
|
||||
jsonschema "^1.2.0"
|
||||
lodash.values "^4.3.0"
|
||||
|
||||
"@types/fs-extra@^4.0.0":
|
||||
version "4.0.4"
|
||||
resolved "https://registry.yarnpkg.com/@types/fs-extra/-/fs-extra-4.0.4.tgz#72947e108f2cbeda5ab288a927399fdf6d02bd42"
|
||||
@ -36,7 +29,19 @@
|
||||
dependencies:
|
||||
jsonschema "*"
|
||||
|
||||
"@types/lodash@^4.14.37", "@types/lodash@^4.14.64", "@types/lodash@^4.14.78":
|
||||
"@types/lodash.foreach@^4.5.3":
|
||||
version "4.5.3"
|
||||
resolved "https://registry.yarnpkg.com/@types/lodash.foreach/-/lodash.foreach-4.5.3.tgz#87c01a0c5d9d17eec936ca3c28897af79440cdfc"
|
||||
dependencies:
|
||||
"@types/lodash" "*"
|
||||
|
||||
"@types/lodash.values@^4.3.3":
|
||||
version "4.3.3"
|
||||
resolved "https://registry.yarnpkg.com/@types/lodash.values/-/lodash.values-4.3.3.tgz#910edc65b391782d65dc4b4d8804a0dabc5370e6"
|
||||
dependencies:
|
||||
"@types/lodash" "*"
|
||||
|
||||
"@types/lodash@*", "@types/lodash@^4.14.37", "@types/lodash@^4.14.64", "@types/lodash@^4.14.78":
|
||||
version "4.14.85"
|
||||
resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.85.tgz#a16fbf942422f6eca5622b6910492c496c35069b"
|
||||
|
||||
@ -1119,7 +1124,7 @@ chai-typescript-typings@^0.0.1:
|
||||
version "0.0.1"
|
||||
resolved "https://registry.yarnpkg.com/chai-typescript-typings/-/chai-typescript-typings-0.0.1.tgz#433dee303b0b2978ad0dd03129df0a5afb791274"
|
||||
|
||||
chai@^4.0.1:
|
||||
chai@^4.0.1, chai@^4.1.1:
|
||||
version "4.1.2"
|
||||
resolved "https://registry.yarnpkg.com/chai/-/chai-4.1.2.tgz#0f64584ba642f0f2ace2806279f4f06ca23ad73c"
|
||||
dependencies:
|
||||
@ -3547,6 +3552,10 @@ lodash.assign@^4.0.3, lodash.assign@^4.0.6:
|
||||
version "4.2.0"
|
||||
resolved "https://registry.yarnpkg.com/lodash.assign/-/lodash.assign-4.2.0.tgz#0d99f3ccd7a6d261d19bdaeb9245005d285808e7"
|
||||
|
||||
lodash.foreach@^4.5.0:
|
||||
version "4.5.0"
|
||||
resolved "https://registry.yarnpkg.com/lodash.foreach/-/lodash.foreach-4.5.0.tgz#1a6a35eace401280c7f06dddec35165ab27e3e53"
|
||||
|
||||
lodash.get@^4.4.2:
|
||||
version "4.4.2"
|
||||
resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99"
|
||||
|
Loading…
x
Reference in New Issue
Block a user