Throw a better error message when taker is null|undefined or anything but not a string
This commit is contained in:
@@ -25,6 +25,7 @@ import {
|
|||||||
import {AbiDecoder} from './utils/abi_decoder';
|
import {AbiDecoder} from './utils/abi_decoder';
|
||||||
import {assert} from './utils/assert';
|
import {assert} from './utils/assert';
|
||||||
import {constants} from './utils/constants';
|
import {constants} from './utils/constants';
|
||||||
|
import {decorators} from './utils/decorators';
|
||||||
import {signatureUtils} from './utils/signature_utils';
|
import {signatureUtils} from './utils/signature_utils';
|
||||||
import {utils} from './utils/utils';
|
import {utils} from './utils/utils';
|
||||||
|
|
||||||
@@ -155,6 +156,7 @@ export class ZeroEx {
|
|||||||
* @param order An object that conforms to the Order or SignedOrder interface definitions.
|
* @param order An object that conforms to the Order or SignedOrder interface definitions.
|
||||||
* @return The resulting orderHash from hashing the supplied order.
|
* @return The resulting orderHash from hashing the supplied order.
|
||||||
*/
|
*/
|
||||||
|
@decorators.syncZeroExErrorHandler
|
||||||
public static getOrderHashHex(order: Order|SignedOrder): string {
|
public static getOrderHashHex(order: Order|SignedOrder): string {
|
||||||
assert.doesConformToSchema('order', order, schemas.orderSchema);
|
assert.doesConformToSchema('order', order, schemas.orderSchema);
|
||||||
const orderHashHex = utils.getOrderHashHex(order);
|
const orderHashHex = utils.getOrderHashHex(order);
|
||||||
|
|||||||
@@ -162,7 +162,7 @@ export class ExchangeWrapper extends ContractWrapper {
|
|||||||
* @param orderTransactionOpts Optional arguments this method accepts.
|
* @param orderTransactionOpts Optional arguments this method accepts.
|
||||||
* @return Transaction hash.
|
* @return Transaction hash.
|
||||||
*/
|
*/
|
||||||
@decorators.contractCallErrorHandler
|
@decorators.asyncZeroExErrorHandler
|
||||||
public async fillOrderAsync(signedOrder: SignedOrder, fillTakerTokenAmount: BigNumber,
|
public async fillOrderAsync(signedOrder: SignedOrder, fillTakerTokenAmount: BigNumber,
|
||||||
shouldThrowOnInsufficientBalanceOrAllowance: boolean,
|
shouldThrowOnInsufficientBalanceOrAllowance: boolean,
|
||||||
takerAddress: string,
|
takerAddress: string,
|
||||||
@@ -218,7 +218,7 @@ export class ExchangeWrapper extends ContractWrapper {
|
|||||||
* @param orderTransactionOpts Optional arguments this method accepts.
|
* @param orderTransactionOpts Optional arguments this method accepts.
|
||||||
* @return Transaction hash.
|
* @return Transaction hash.
|
||||||
*/
|
*/
|
||||||
@decorators.contractCallErrorHandler
|
@decorators.asyncZeroExErrorHandler
|
||||||
public async fillOrdersUpToAsync(signedOrders: SignedOrder[], fillTakerTokenAmount: BigNumber,
|
public async fillOrdersUpToAsync(signedOrders: SignedOrder[], fillTakerTokenAmount: BigNumber,
|
||||||
shouldThrowOnInsufficientBalanceOrAllowance: boolean,
|
shouldThrowOnInsufficientBalanceOrAllowance: boolean,
|
||||||
takerAddress: string,
|
takerAddress: string,
|
||||||
@@ -299,7 +299,7 @@ export class ExchangeWrapper extends ContractWrapper {
|
|||||||
* @param orderTransactionOpts Optional arguments this method accepts.
|
* @param orderTransactionOpts Optional arguments this method accepts.
|
||||||
* @return Transaction hash.
|
* @return Transaction hash.
|
||||||
*/
|
*/
|
||||||
@decorators.contractCallErrorHandler
|
@decorators.asyncZeroExErrorHandler
|
||||||
public async batchFillOrdersAsync(orderFillRequests: OrderFillRequest[],
|
public async batchFillOrdersAsync(orderFillRequests: OrderFillRequest[],
|
||||||
shouldThrowOnInsufficientBalanceOrAllowance: boolean,
|
shouldThrowOnInsufficientBalanceOrAllowance: boolean,
|
||||||
takerAddress: string,
|
takerAddress: string,
|
||||||
@@ -372,7 +372,7 @@ export class ExchangeWrapper extends ContractWrapper {
|
|||||||
* @param orderTransactionOpts Optional arguments this method accepts.
|
* @param orderTransactionOpts Optional arguments this method accepts.
|
||||||
* @return Transaction hash.
|
* @return Transaction hash.
|
||||||
*/
|
*/
|
||||||
@decorators.contractCallErrorHandler
|
@decorators.asyncZeroExErrorHandler
|
||||||
public async fillOrKillOrderAsync(signedOrder: SignedOrder, fillTakerTokenAmount: BigNumber,
|
public async fillOrKillOrderAsync(signedOrder: SignedOrder, fillTakerTokenAmount: BigNumber,
|
||||||
takerAddress: string,
|
takerAddress: string,
|
||||||
orderTransactionOpts: OrderTransactionOpts = {}): Promise<string> {
|
orderTransactionOpts: OrderTransactionOpts = {}): Promise<string> {
|
||||||
@@ -417,7 +417,7 @@ export class ExchangeWrapper extends ContractWrapper {
|
|||||||
* @param orderTransactionOpts Optional arguments this method accepts.
|
* @param orderTransactionOpts Optional arguments this method accepts.
|
||||||
* @return Transaction hash.
|
* @return Transaction hash.
|
||||||
*/
|
*/
|
||||||
@decorators.contractCallErrorHandler
|
@decorators.asyncZeroExErrorHandler
|
||||||
public async batchFillOrKillAsync(orderFillRequests: OrderFillRequest[],
|
public async batchFillOrKillAsync(orderFillRequests: OrderFillRequest[],
|
||||||
takerAddress: string,
|
takerAddress: string,
|
||||||
orderTransactionOpts: OrderTransactionOpts = {}): Promise<string> {
|
orderTransactionOpts: OrderTransactionOpts = {}): Promise<string> {
|
||||||
@@ -485,7 +485,7 @@ export class ExchangeWrapper extends ContractWrapper {
|
|||||||
* @param transactionOpts Optional arguments this method accepts.
|
* @param transactionOpts Optional arguments this method accepts.
|
||||||
* @return Transaction hash.
|
* @return Transaction hash.
|
||||||
*/
|
*/
|
||||||
@decorators.contractCallErrorHandler
|
@decorators.asyncZeroExErrorHandler
|
||||||
public async cancelOrderAsync(order: Order|SignedOrder,
|
public async cancelOrderAsync(order: Order|SignedOrder,
|
||||||
cancelTakerTokenAmount: BigNumber,
|
cancelTakerTokenAmount: BigNumber,
|
||||||
orderTransactionOpts: OrderTransactionOpts = {}): Promise<string> {
|
orderTransactionOpts: OrderTransactionOpts = {}): Promise<string> {
|
||||||
@@ -526,7 +526,7 @@ export class ExchangeWrapper extends ContractWrapper {
|
|||||||
* @param transactionOpts Optional arguments this method accepts.
|
* @param transactionOpts Optional arguments this method accepts.
|
||||||
* @return Transaction hash.
|
* @return Transaction hash.
|
||||||
*/
|
*/
|
||||||
@decorators.contractCallErrorHandler
|
@decorators.asyncZeroExErrorHandler
|
||||||
public async batchCancelOrdersAsync(orderCancellationRequests: OrderCancellationRequest[],
|
public async batchCancelOrdersAsync(orderCancellationRequests: OrderCancellationRequest[],
|
||||||
orderTransactionOpts: OrderTransactionOpts = {}): Promise<string> {
|
orderTransactionOpts: OrderTransactionOpts = {}): Promise<string> {
|
||||||
assert.doesConformToSchema('orderCancellationRequests', orderCancellationRequests,
|
assert.doesConformToSchema('orderCancellationRequests', orderCancellationRequests,
|
||||||
|
|||||||
@@ -235,6 +235,7 @@ export interface OrderFillRequest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export type AsyncMethod = (...args: any[]) => Promise<any>;
|
export type AsyncMethod = (...args: any[]) => Promise<any>;
|
||||||
|
export type SyncMethod = (...args: any[]) => any;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* We re-export the `Web3.Provider` type specified in the Web3 Typescript typings
|
* We re-export the `Web3.Provider` type specified in the Web3 Typescript typings
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ export const constants = {
|
|||||||
MAX_DIGITS_IN_UNSIGNED_256_INT: 78,
|
MAX_DIGITS_IN_UNSIGNED_256_INT: 78,
|
||||||
INVALID_JUMP_PATTERN: 'invalid JUMP at',
|
INVALID_JUMP_PATTERN: 'invalid JUMP at',
|
||||||
OUT_OF_GAS_PATTERN: 'out of gas',
|
OUT_OF_GAS_PATTERN: 'out of gas',
|
||||||
|
INVALID_TAKER_FORMAT: 'instance.taker is not of a type(s) string',
|
||||||
UNLIMITED_ALLOWANCE_IN_BASE_UNITS: new BigNumber(2).pow(256).minus(1),
|
UNLIMITED_ALLOWANCE_IN_BASE_UNITS: new BigNumber(2).pow(256).minus(1),
|
||||||
DEFAULT_BLOCK_POLLING_INTERVAL: 1000,
|
DEFAULT_BLOCK_POLLING_INTERVAL: 1000,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,17 +1,37 @@
|
|||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
|
|
||||||
import {AsyncMethod, ZeroExError} from '../types';
|
import {AsyncMethod, SyncMethod, ZeroExError} from '../types';
|
||||||
|
|
||||||
import {constants} from './constants';
|
import {constants} from './constants';
|
||||||
|
|
||||||
export const decorators = {
|
type ErrorTransformer = (err: Error) => Error;
|
||||||
/**
|
|
||||||
* Source: https://stackoverflow.com/a/29837695/3546986
|
const contractCallErrorTransformer = (error: Error) => {
|
||||||
*/
|
if (_.includes(error.message, constants.INVALID_JUMP_PATTERN)) {
|
||||||
contractCallErrorHandler(target: object,
|
return new Error(ZeroExError.InvalidJump);
|
||||||
key: string|symbol,
|
}
|
||||||
descriptor: TypedPropertyDescriptor<AsyncMethod>,
|
if (_.includes(error.message, constants.OUT_OF_GAS_PATTERN)) {
|
||||||
): TypedPropertyDescriptor<AsyncMethod> {
|
return new Error(ZeroExError.OutOfGas);
|
||||||
|
}
|
||||||
|
return error;
|
||||||
|
};
|
||||||
|
|
||||||
|
const schemaErrorTransformer = (error: Error) => {
|
||||||
|
if (_.includes(error.message, constants.INVALID_TAKER_FORMAT)) {
|
||||||
|
// tslint:disable-next-line:max-line-length
|
||||||
|
const errMsg = 'Order taker must be of type string. If you want anyone to be able to fill an order - pass ZeroEx.NULL_ADDRESS';
|
||||||
|
throw new Error(errMsg);
|
||||||
|
}
|
||||||
|
return error;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Source: https://stackoverflow.com/a/29837695/3546986
|
||||||
|
*/
|
||||||
|
const asyncErrorHandlerFactory = (errorTransformer: ErrorTransformer) => {
|
||||||
|
const asyncErrorHandlingDecorator = (
|
||||||
|
target: object, key: string|symbol, descriptor: TypedPropertyDescriptor<AsyncMethod>,
|
||||||
|
) => {
|
||||||
const originalMethod = (descriptor.value as AsyncMethod);
|
const originalMethod = (descriptor.value as AsyncMethod);
|
||||||
|
|
||||||
// Do not use arrow syntax here. Use a function expression in
|
// Do not use arrow syntax here. Use a function expression in
|
||||||
@@ -22,16 +42,46 @@ export const decorators = {
|
|||||||
const result = await originalMethod.apply(this, args);
|
const result = await originalMethod.apply(this, args);
|
||||||
return result;
|
return result;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (_.includes(error.message, constants.INVALID_JUMP_PATTERN)) {
|
const transformedError = errorTransformer(error);
|
||||||
throw new Error(ZeroExError.InvalidJump);
|
throw transformedError;
|
||||||
}
|
|
||||||
if (_.includes(error.message, constants.OUT_OF_GAS_PATTERN)) {
|
|
||||||
throw new Error(ZeroExError.OutOfGas);
|
|
||||||
}
|
|
||||||
throw error;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return descriptor;
|
return descriptor;
|
||||||
},
|
};
|
||||||
|
|
||||||
|
return asyncErrorHandlingDecorator;
|
||||||
|
};
|
||||||
|
|
||||||
|
const syncErrorHandlerFactory = (errorTransformer: ErrorTransformer) => {
|
||||||
|
const syncErrorHandlingDecorator = (
|
||||||
|
target: object, key: string|symbol, descriptor: TypedPropertyDescriptor<SyncMethod>,
|
||||||
|
) => {
|
||||||
|
const originalMethod = (descriptor.value as SyncMethod);
|
||||||
|
|
||||||
|
// Do not use arrow syntax here. Use a function expression in
|
||||||
|
// order to use the correct value of `this` in this method
|
||||||
|
// tslint:disable-next-line:only-arrow-functions
|
||||||
|
descriptor.value = function(...args: any[]) {
|
||||||
|
try {
|
||||||
|
const result = originalMethod.apply(this, args);
|
||||||
|
return result;
|
||||||
|
} catch (error) {
|
||||||
|
const transformedError = errorTransformer(error);
|
||||||
|
throw transformedError;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return descriptor;
|
||||||
|
};
|
||||||
|
|
||||||
|
return syncErrorHandlingDecorator;
|
||||||
|
};
|
||||||
|
|
||||||
|
// _.flow(f, g) = f ∘ g
|
||||||
|
const zeroExErrorTransformer = _.flow(schemaErrorTransformer, contractCallErrorTransformer);
|
||||||
|
|
||||||
|
export const decorators = {
|
||||||
|
asyncZeroExErrorHandler: asyncErrorHandlerFactory(zeroExErrorTransformer),
|
||||||
|
syncZeroExErrorHandler: syncErrorHandlerFactory(zeroExErrorTransformer),
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -152,6 +152,15 @@ describe('ZeroEx library', () => {
|
|||||||
const orderHash = ZeroEx.getOrderHashHex(order);
|
const orderHash = ZeroEx.getOrderHashHex(order);
|
||||||
expect(orderHash).to.be.equal(expectedOrderHash);
|
expect(orderHash).to.be.equal(expectedOrderHash);
|
||||||
});
|
});
|
||||||
|
it('throws a readable error message if taker format is invalid', async () => {
|
||||||
|
const orderWithInvalidtakerFormat = {
|
||||||
|
...order,
|
||||||
|
taker: null as any as string,
|
||||||
|
};
|
||||||
|
// tslint:disable-next-line:max-line-length
|
||||||
|
const expectedErrorMessage = 'Order taker must be of type string. If you want anyone to be able to fill an order - pass ZeroEx.NULL_ADDRESS';
|
||||||
|
expect(() => ZeroEx.getOrderHashHex(orderWithInvalidtakerFormat)).to.throw(expectedErrorMessage);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
describe('#signOrderHashAsync', () => {
|
describe('#signOrderHashAsync', () => {
|
||||||
let stubs: Sinon.SinonStub[] = [];
|
let stubs: Sinon.SinonStub[] = [];
|
||||||
|
|||||||
Reference in New Issue
Block a user