updated order coercion utils architecture and testing

This commit is contained in:
David Sun 2019-02-07 16:45:56 -05:00
parent d95af455f1
commit 6dabed5938
8 changed files with 180 additions and 4544 deletions

View File

@ -17,8 +17,8 @@ import { ZeroExInstantOverlay, ZeroExInstantOverlayProps } from './index';
import { Network, OrderSource } from './types';
import { analytics } from './util/analytics';
import { assert } from './util/assert';
import { orderCoercionUtil } from './util/order_coercion';
import { providerFactory } from './util/provider_factory';
import { signedOrderCoercionUtil } from './util/signed_order_coercion';
import { util } from './util/util';
const isInstantRendered = (): boolean => !!document.getElementById(INJECTED_DIV_ID);
@ -94,8 +94,8 @@ export interface ZeroExInstantConfig extends ZeroExInstantOverlayProps {
}
export const render = (config: ZeroExInstantConfig, selector: string = DEFAULT_ZERO_EX_CONTAINER_SELECTOR) => {
if (!_.isString(config.orderSource)) {
config.orderSource = config.orderSource.map(signedOrderCoercionUtil.bigNumberCoercion);
if (_.isArray(config.orderSource)) {
config.orderSource = orderCoercionUtil.coerceOrderArrayFieldsToBigNumber(config.orderSource);
}
validateInstantRenderConfig(config, selector);

View File

@ -16,8 +16,14 @@ export const maybeBigNumberUtil = {
return validBigNumber.isNaN() ? undefined : validBigNumber;
},
areMaybeBigNumbersEqual: (val1: Maybe<BigNumber>, val2: Maybe<BigNumber>): boolean => {
if (!_.isUndefined(val1) && !_.isUndefined(val2)) {
return val1.isEqualTo(val2);
}
return _.isUndefined(val1) && _.isUndefined(val2);
},
// converts a BigNumber or String to the BigNumber used by 0x libraries
bigNumberOrStringToMaybeBigNumber: (value: any): Maybe<BigNumber> => {
toMaybeBigNumber: (value: any): Maybe<BigNumber> => {
if (_.isString(value)) {
return maybeBigNumberUtil.stringToMaybeBigNumber(value);
}
@ -27,10 +33,4 @@ export const maybeBigNumberUtil = {
}
return undefined;
},
areMaybeBigNumbersEqual: (val1: Maybe<BigNumber>, val2: Maybe<BigNumber>): boolean => {
if (!_.isUndefined(val1) && !_.isUndefined(val2)) {
return val1.isEqualTo(val2);
}
return _.isUndefined(val1) && _.isUndefined(val2);
},
};

View File

@ -0,0 +1,42 @@
import { BigNumber } from '@0x/utils';
import * as _ from 'lodash';
import { maybeBigNumberUtil } from './maybe_big_number';
const coerceBigNumberOrString = (value: any): BigNumber => {
const bn = maybeBigNumberUtil.toMaybeBigNumber(value);
return !!bn ? bn : value;
};
// function implies that the signed order already has been validated
export const orderCoercionUtil = {
// coerces order big number values to the BigNumber version utilized by 0x
coerceFieldsToBigNumbers(obj: any, fields: string[]): any {
const result = _.assign({}, obj);
_.each(fields, field => {
_.update(result, field, (value: string) => {
if (_.isUndefined(value)) {
throw new Error(`Could not find field '${field}' while converting fields to BigNumber.`);
}
return coerceBigNumberOrString(value);
});
});
return result;
},
coerceOrderFieldsToBigNumber: (order: any): any => {
return orderCoercionUtil.coerceFieldsToBigNumbers(order, [
'makerFee',
'takerFee',
'makerAssetAmount',
'takerAssetAmount',
'salt',
'expirationTimeSeconds',
]);
},
coerceOrderArrayFieldsToBigNumber: (orders: any[]): any[] => {
return _.map(orders, (value: any) => {
return orderCoercionUtil.coerceOrderFieldsToBigNumber(value);
});
},
};

View File

@ -1,26 +0,0 @@
import { SignedOrder } from '@0x/types';
import { BigNumber } from '@0x/utils';
import * as _ from 'lodash';
import { maybeBigNumberUtil } from './maybe_big_number';
const coerceBigNumberOrString = (value: any): BigNumber => {
const bn = maybeBigNumberUtil.bigNumberOrStringToMaybeBigNumber(value);
return !!bn ? bn : value;
};
// function implies that the signed order already has been validated
export const signedOrderCoercionUtil = {
// coerces order big number values to the BigNumber version utilized by 0x
bigNumberCoercion: (order: SignedOrder): SignedOrder => {
return {
...order,
makerFee: coerceBigNumberOrString(order.makerFee),
takerFee: coerceBigNumberOrString(order.takerFee),
makerAssetAmount: coerceBigNumberOrString(order.makerAssetAmount),
takerAssetAmount: coerceBigNumberOrString(order.takerAssetAmount),
salt: coerceBigNumberOrString(order.salt),
expirationTimeSeconds: coerceBigNumberOrString(order.expirationTimeSeconds),
};
},
};

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -2,12 +2,9 @@ import { BigNumber } from '@0x/utils';
import { maybeBigNumberUtil } from '../../src/util/maybe_big_number';
// import PrevBigNumber from './dependencies/prevbignumber';
const BIG_NUMBER_1 = new BigNumber('10.1');
const BIG_NUMBER_2 = new BigNumber('10.1');
const BIG_NUMBER_3 = new BigNumber('11.1');
// const PREVBIG_NUMBER_1 = new PrevBigNumber('11.1');
describe('maybeBigNumberUtil', () => {
describe('stringToMaybeBigNumber', () => {
@ -40,32 +37,29 @@ describe('maybeBigNumberUtil', () => {
});
});
// describe('bigNumberOrStringToMaybeBigNumber', () => {
// it('should return BigNumber (>=v8.0.0) constructed with value if type is string', () => {
// const bn = maybeBigNumberUtil.bigNumberOrStringToMaybeBigNumber('10.1');
// if (!!bn) {
// expect(bn.toString()).toEqual('10.1');
// }
// });
// it('should return undefined if value is NaN', () => {
// expect(maybeBigNumberUtil.bigNumberOrStringToMaybeBigNumber('NaN')).toEqual(undefined);
// });
// it('should return undefined if value as string is not valid (i.e not numeric)', () => {
// expect(maybeBigNumberUtil.bigNumberOrStringToMaybeBigNumber('test')).toEqual(undefined);
// });
// it('should return undefined if value as string is not valid (i.e not numeric)', () => {
// expect(maybeBigNumberUtil.bigNumberOrStringToMaybeBigNumber('test')).toEqual(undefined);
// });
// it('should return BigNumber (>=v8.0.0) when passed a value as BigNumber (<v8.0.0)', () => {
// const bn = maybeBigNumberUtil.bigNumberOrStringToMaybeBigNumber(PREVBIG_NUMBER_1);
// expect(BigNumber.isBigNumber(bn)).toEqual(true);
// });
// it('should return BigNumber (>=v8.0.0) when passed a value as BigNumber (>=v8.0.0)', () => {
// const bn = maybeBigNumberUtil.bigNumberOrStringToMaybeBigNumber(BIG_NUMBER_1);
// expect(BigNumber.isBigNumber(bn)).toEqual(true);
// });
// it('should return undefined if value is not BigNumber or string', () => {
// expect(maybeBigNumberUtil.bigNumberOrStringToMaybeBigNumber(true)).toEqual(undefined);
// });
// });
// this doesn't test coercing a pre v8.0.0 version of big number to desired version
describe('toMaybeBigNumber', () => {
it('should return BigNumber (>=v8.0.0) constructed with value if type is string', () => {
const bn = maybeBigNumberUtil.toMaybeBigNumber('10.1');
if (!!bn) {
expect(bn.toString()).toEqual('10.1');
}
});
it('should return undefined if value is NaN', () => {
expect(maybeBigNumberUtil.toMaybeBigNumber('NaN')).toEqual(undefined);
});
it('should return undefined if value as string is not valid (i.e not numeric)', () => {
expect(maybeBigNumberUtil.toMaybeBigNumber('test')).toEqual(undefined);
});
it('should return undefined if value as string is not valid (i.e not numeric)', () => {
expect(maybeBigNumberUtil.toMaybeBigNumber('test')).toEqual(undefined);
});
it('should return BigNumber (>=v8.0.0) when passed a value as BigNumber (>=v8.0.0)', () => {
const bn = maybeBigNumberUtil.toMaybeBigNumber(BIG_NUMBER_1);
expect(BigNumber.isBigNumber(bn)).toEqual(true);
});
it('should return undefined if value is not BigNumber or string', () => {
expect(maybeBigNumberUtil.toMaybeBigNumber(true)).toEqual(undefined);
});
});
});

View File

@ -0,0 +1,103 @@
import { BigNumber } from '@0x/utils';
import { orderCoercionUtil } from '../../src/util/order_coercion';
const ORDER = {
senderAddress: '0x0000000000000000000000000000000000000000',
makerAddress: '0x34a745008a643eebc58920eaa29fb1165b4a288e',
takerAddress: '0x0000000000000000000000000000000000000000',
makerFee: new BigNumber('0'),
takerFee: new BigNumber('0'),
makerAssetAmount: new BigNumber('200000000000000000000'),
takerAssetAmount: new BigNumber('10000000000000000000'),
makerAssetData: '0xf47261b00000000000000000000000008cb3971b8eb709c14616bd556ff6683019e90d9c',
takerAssetData: '0xf47261b0000000000000000000000000d0a1e359811322d97991e03f863a0c30c2cf029c',
expirationTimeSeconds: new BigNumber('1601535600'),
feeRecipientAddress: '0x0000000000000000000000000000000000000000',
salt: new BigNumber('3101985707338942582579795423923841749956600670712030922928319824580764688653'),
signature:
'0x1bd4d5686fea801fe33c68c4944356085e7e6cb553eb7073160abd815609f714e85fb47f44b7ffd0a2a1321ac40d72d55163869d0a50fdb5a402132150fe33a08403',
exchangeAddress: '0x35dd2932454449b14cee11a94d3674a936d5d7b2',
};
const STRING_ORDER = {
senderAddress: '0x0000000000000000000000000000000000000000',
makerAddress: '0x34a745008a643eebc58920eaa29fb1165b4a288e',
takerAddress: '0x0000000000000000000000000000000000000000',
makerFee: '0',
takerFee: '0',
makerAssetAmount: '300000000000000000000',
takerAssetAmount: '31000000000000000000',
makerAssetData: '0xf47261b00000000000000000000000002002d3812f58e35f0ea1ffbf80a75a38c32175fa',
takerAssetData: '0xf47261b0000000000000000000000000d0a1e359811322d97991e03f863a0c30c2cf029c',
expirationTimeSeconds: '2524636800',
feeRecipientAddress: '0x0000000000000000000000000000000000000000',
salt: '64592004666704945574675477805199411288137454783320798602050822322450089238268',
signature:
'0x1c13cacddca8d7d8248e91f412377e68f8f1f9891a59a6c1b2eea9f7b33558c30c4fb86a448e08ab7def40a28fb3a3062dcb33bb3c45302447fce5c4288b7c7f5b03',
exchangeAddress: '0x35dd2932454449b14cee11a94d3674a936d5d7b2',
};
const ORDERS = [ORDER, STRING_ORDER];
describe('orderCoercionUtil', () => {
describe('coerceFieldsToBigNumbers', () => {
it('should coerce all fields specified to a big number', () => {
const coercedOrder = orderCoercionUtil.coerceFieldsToBigNumbers(STRING_ORDER, ['makerFee', 'takerFee']);
expect(coercedOrder.makerFee.toString()).toEqual('0');
expect(coercedOrder.takerFee.toString()).toEqual('0');
});
it("should throw if a field can't be found", () => {
expect(() => {
orderCoercionUtil.coerceFieldsToBigNumbers(ORDER, ['salty']);
}).toThrow("Could not find field 'salty' while converting fields to BigNumber.");
});
it('should not change value if not numeric string or big number', () => {
const obj = { number: 'number' };
const coercedObj = orderCoercionUtil.coerceFieldsToBigNumbers(obj, ['number']);
expect(coercedObj).toEqual({
number: 'number',
});
});
});
// Note: this doesn't test coercing pre v8.0.0 BigNumber versions to specified one used by 0x
describe('coerceOrderFieldsToBigNumber', () => {
it('should convert string values in order to big number', () => {
const coercedOrder = orderCoercionUtil.coerceOrderFieldsToBigNumber(STRING_ORDER);
expect(coercedOrder.makerFee.toString()).toEqual(STRING_ORDER.makerFee);
expect(coercedOrder.takerFee.toString()).toEqual(STRING_ORDER.takerFee);
expect(coercedOrder.takerAssetAmount.toString()).toEqual(STRING_ORDER.takerAssetAmount);
expect(coercedOrder.makerAssetAmount.toString()).toEqual(STRING_ORDER.makerAssetAmount);
expect(coercedOrder.salt.toString()).toEqual(STRING_ORDER.salt);
expect(coercedOrder.expirationTimeSeconds.toString()).toEqual(STRING_ORDER.expirationTimeSeconds);
});
it('should convert big number values in order to big number', () => {
const coercedOrder = orderCoercionUtil.coerceOrderFieldsToBigNumber(ORDER);
expect(coercedOrder.makerFee).toEqual(ORDER.makerFee);
expect(coercedOrder.takerFee).toEqual(ORDER.takerFee);
expect(coercedOrder.takerAssetAmount).toEqual(ORDER.takerAssetAmount);
expect(coercedOrder.makerAssetAmount).toEqual(ORDER.makerAssetAmount);
expect(coercedOrder.salt).toEqual(ORDER.salt);
expect(coercedOrder.expirationTimeSeconds).toEqual(ORDER.expirationTimeSeconds);
});
});
// Note: this doesn't test coercing pre v8.0.0 BigNumber versions to specified one used by 0x
describe('coerceOrderArrayFieldsToBigNumber', () => {
it('should convert string values and big numbers in orders to big number', () => {
const coercedOrders = orderCoercionUtil.coerceOrderArrayFieldsToBigNumber(ORDERS);
expect(coercedOrders[0].makerFee).toEqual(ORDER.makerFee);
expect(coercedOrders[0].takerFee).toEqual(ORDER.takerFee);
expect(coercedOrders[0].takerAssetAmount).toEqual(ORDER.takerAssetAmount);
expect(coercedOrders[0].makerAssetAmount).toEqual(ORDER.makerAssetAmount);
expect(coercedOrders[0].salt).toEqual(ORDER.salt);
expect(coercedOrders[0].expirationTimeSeconds).toEqual(ORDER.expirationTimeSeconds);
expect(coercedOrders[1].makerFee.toString()).toEqual(STRING_ORDER.makerFee);
expect(coercedOrders[1].takerFee.toString()).toEqual(STRING_ORDER.takerFee);
expect(coercedOrders[1].takerAssetAmount.toString()).toEqual(STRING_ORDER.takerAssetAmount);
expect(coercedOrders[1].makerAssetAmount.toString()).toEqual(STRING_ORDER.makerAssetAmount);
expect(coercedOrders[1].salt.toString()).toEqual(STRING_ORDER.salt);
expect(coercedOrders[1].expirationTimeSeconds.toString()).toEqual(STRING_ORDER.expirationTimeSeconds);
});
});
});