Apply prettier config

This commit is contained in:
Leonid Logvinov 2017-12-22 15:05:32 +01:00
parent 9a96e8c704
commit e744e4cd98
No known key found for this signature in database
GPG Key ID: 0DD294BFDE8C95D4
284 changed files with 6783 additions and 6205 deletions

View File

@ -26,3 +26,4 @@ jobs:
background: true background: true
- run: yarn lerna:run test:circleci - run: yarn lerna:run test:circleci
- run: yarn lerna:run lint - run: yarn lerna:run lint
- run: yarn prettier:ci

2
.prettierignore Normal file
View File

@ -0,0 +1,2 @@
lib
generated

6
.prettierrc Normal file
View File

@ -0,0 +1,6 @@
{
"tabWidth": 4,
"printWidth": 120,
"trailingComma": all,
"singleQuote": true
}

View File

@ -1,15 +1,15 @@
{ {
"private": true, "private": true,
"name": "0x.js", "name": "0x.js",
"workspaces": [ "workspaces": ["packages/*"],
"packages/*"
],
"scripts": { "scripts": {
"testrpc": "testrpc -p 8545 --networkId 50 -m \"${npm_package_config_mnemonic}\"", "testrpc": "testrpc -p 8545 --networkId 50 -m \"${npm_package_config_mnemonic}\"",
"prettier": "prettier --write '**/*.ts'", "prettier": "prettier --write '**/*.{ts,tsx}'",
"prettier:ci": "prettier --list-different '**/*.{ts,tsx}'",
"lerna:run": "lerna run", "lerna:run": "lerna run",
"lerna:rebuild": "lerna run clean; lerna run build;", "lerna:rebuild": "lerna run clean; lerna run build;",
"lerna:publish": "yarn install; lerna run clean; lerna run build; lerna publish --registry=https://registry.npmjs.org/" "lerna:publish":
"yarn install; lerna run clean; lerna run build; lerna publish --registry=https://registry.npmjs.org/"
}, },
"config": { "config": {
"mnemonic": "concert load couple harbor equip island argue ramp clarify fence smart topic" "mnemonic": "concert load couple harbor equip island argue ramp clarify fence smart topic"

View File

@ -188,12 +188,7 @@ export class ZeroEx {
config.networkId, config.networkId,
config.tokenTransferProxyContractAddress, config.tokenTransferProxyContractAddress,
); );
this.token = new TokenWrapper( this.token = new TokenWrapper(this._web3Wrapper, config.networkId, this._abiDecoder, this.proxy);
this._web3Wrapper,
config.networkId,
this._abiDecoder,
this.proxy,
);
this.exchange = new ExchangeWrapper( this.exchange = new ExchangeWrapper(
this._web3Wrapper, this._web3Wrapper,
config.networkId, config.networkId,
@ -202,13 +197,17 @@ export class ZeroEx {
config.exchangeContractAddress, config.exchangeContractAddress,
); );
this.tokenRegistry = new TokenRegistryWrapper( this.tokenRegistry = new TokenRegistryWrapper(
this._web3Wrapper, config.networkId, config.tokenRegistryContractAddress, this._web3Wrapper,
); config.networkId,
this.etherToken = new EtherTokenWrapper( config.tokenRegistryContractAddress,
this._web3Wrapper, config.networkId, this._abiDecoder, this.token,
); );
this.etherToken = new EtherTokenWrapper(this._web3Wrapper, config.networkId, this._abiDecoder, this.token);
this.orderStateWatcher = new OrderStateWatcher( this.orderStateWatcher = new OrderStateWatcher(
this._web3Wrapper, this._abiDecoder, this.token, this.exchange, config.orderWatcherConfig, this._web3Wrapper,
this._abiDecoder,
this.token,
this.exchange,
config.orderWatcherConfig,
); );
} }
/** /**
@ -291,10 +290,13 @@ export class ZeroEx {
* @return Transaction receipt with decoded log args. * @return Transaction receipt with decoded log args.
*/ */
public async awaitTransactionMinedAsync( public async awaitTransactionMinedAsync(
txHash: string, pollingIntervalMs = 1000, timeoutMs?: number): Promise<TransactionReceiptWithDecodedLogs> { txHash: string,
pollingIntervalMs = 1000,
timeoutMs?: number,
): Promise<TransactionReceiptWithDecodedLogs> {
let timeoutExceeded = false; let timeoutExceeded = false;
if (timeoutMs) { if (timeoutMs) {
setTimeout(() => timeoutExceeded = true, timeoutMs); setTimeout(() => (timeoutExceeded = true), timeoutMs);
} }
const txReceiptPromise = new Promise( const txReceiptPromise = new Promise(
@ -319,7 +321,8 @@ export class ZeroEx {
resolve(transactionReceiptWithDecodedLogArgs); resolve(transactionReceiptWithDecodedLogArgs);
} }
}, pollingIntervalMs); }, pollingIntervalMs);
}); },
);
return txReceiptPromise; return txReceiptPromise;
} }

View File

@ -8,11 +8,11 @@ import * as ZRXArtifact from './artifacts/ZRX.json';
import { Artifact } from './types'; import { Artifact } from './types';
export const artifacts = { export const artifacts = {
ZRXArtifact: ZRXArtifact as any as Artifact, ZRXArtifact: (ZRXArtifact as any) as Artifact,
DummyTokenArtifact: DummyTokenArtifact as any as Artifact, DummyTokenArtifact: (DummyTokenArtifact as any) as Artifact,
TokenArtifact: TokenArtifact as any as Artifact, TokenArtifact: (TokenArtifact as any) as Artifact,
ExchangeArtifact: ExchangeArtifact as any as Artifact, ExchangeArtifact: (ExchangeArtifact as any) as Artifact,
EtherTokenArtifact: EtherTokenArtifact as any as Artifact, EtherTokenArtifact: (EtherTokenArtifact as any) as Artifact,
TokenRegistryArtifact: TokenRegistryArtifact as any as Artifact, TokenRegistryArtifact: (TokenRegistryArtifact as any) as Artifact,
TokenTransferProxyArtifact: TokenTransferProxyArtifact as any as Artifact, TokenTransferProxyArtifact: (TokenTransferProxyArtifact as any) as Artifact,
}; };

View File

@ -21,7 +21,9 @@ import {AbiDecoder} from '../utils/abi_decoder';
import { constants } from '../utils/constants'; import { constants } from '../utils/constants';
import { filterUtils } from '../utils/filter_utils'; import { filterUtils } from '../utils/filter_utils';
const CONTRACT_NAME_TO_NOT_FOUND_ERROR: {[contractName: string]: ZeroExError} = { const CONTRACT_NAME_TO_NOT_FOUND_ERROR: {
[contractName: string]: ZeroExError;
} = {
ZRX: ZeroExError.ZRXContractDoesNotExist, ZRX: ZeroExError.ZRXContractDoesNotExist,
EtherToken: ZeroExError.EtherTokenContractDoesNotExist, EtherToken: ZeroExError.EtherTokenContractDoesNotExist,
Token: ZeroExError.TokenContractDoesNotExist, Token: ZeroExError.TokenContractDoesNotExist,
@ -37,7 +39,9 @@ export class ContractWrapper {
private _blockAndLogStreamerIfExists: BlockAndLogStreamer | undefined; private _blockAndLogStreamerIfExists: BlockAndLogStreamer | undefined;
private _blockAndLogStreamInterval: NodeJS.Timer; private _blockAndLogStreamInterval: NodeJS.Timer;
private _filters: { [filterToken: string]: Web3.FilterObject }; private _filters: { [filterToken: string]: Web3.FilterObject };
private _filterCallbacks: {[filterToken: string]: EventCallback<ContractEventArgs>}; private _filterCallbacks: {
[filterToken: string]: EventCallback<ContractEventArgs>;
};
private _onLogAddedSubscriptionToken: string | undefined; private _onLogAddedSubscriptionToken: string | undefined;
private _onLogRemovedSubscriptionToken: string | undefined; private _onLogRemovedSubscriptionToken: string | undefined;
constructor(web3Wrapper: Web3Wrapper, networkId: number, abiDecoder?: AbiDecoder) { constructor(web3Wrapper: Web3Wrapper, networkId: number, abiDecoder?: AbiDecoder) {
@ -71,8 +75,12 @@ export class ContractWrapper {
} }
} }
protected _subscribe<ArgsType extends ContractEventArgs>( protected _subscribe<ArgsType extends ContractEventArgs>(
address: string, eventName: ContractEvents, indexFilterValues: IndexedFilterValues, abi: Web3.ContractAbi, address: string,
callback: EventCallback<ArgsType>): string { eventName: ContractEvents,
indexFilterValues: IndexedFilterValues,
abi: Web3.ContractAbi,
callback: EventCallback<ArgsType>,
): string {
const filter = filterUtils.getFilter(address, eventName, indexFilterValues, abi); const filter = filterUtils.getFilter(address, eventName, indexFilterValues, abi);
if (_.isUndefined(this._blockAndLogStreamerIfExists)) { if (_.isUndefined(this._blockAndLogStreamerIfExists)) {
this._startBlockAndLogStream(); this._startBlockAndLogStream();
@ -83,15 +91,20 @@ export class ContractWrapper {
return filterToken; return filterToken;
} }
protected async _getLogsAsync<ArgsType extends ContractEventArgs>( protected async _getLogsAsync<ArgsType extends ContractEventArgs>(
address: string, eventName: ContractEvents, blockRange: BlockRange, address: string,
indexFilterValues: IndexedFilterValues, abi: Web3.ContractAbi): Promise<Array<LogWithDecodedArgs<ArgsType>>> { eventName: ContractEvents,
blockRange: BlockRange,
indexFilterValues: IndexedFilterValues,
abi: Web3.ContractAbi,
): Promise<Array<LogWithDecodedArgs<ArgsType>>> {
const filter = filterUtils.getFilter(address, eventName, indexFilterValues, abi, blockRange); const filter = filterUtils.getFilter(address, eventName, indexFilterValues, abi, blockRange);
const logs = await this._web3Wrapper.getLogsAsync(filter); const logs = await this._web3Wrapper.getLogsAsync(filter);
const logsWithDecodedArguments = _.map(logs, this._tryToDecodeLogOrNoop.bind(this)); const logsWithDecodedArguments = _.map(logs, this._tryToDecodeLogOrNoop.bind(this));
return logsWithDecodedArguments; return logsWithDecodedArguments;
} }
protected _tryToDecodeLogOrNoop<ArgsType extends ContractEventArgs>( protected _tryToDecodeLogOrNoop<ArgsType extends ContractEventArgs>(
log: Web3.LogEntry): LogWithDecodedArgs<ArgsType>|RawLog { log: Web3.LogEntry,
): LogWithDecodedArgs<ArgsType> | RawLog {
if (_.isUndefined(this._abiDecoder)) { if (_.isUndefined(this._abiDecoder)) {
throw new Error(InternalZeroExError.NoAbiDecoder); throw new Error(InternalZeroExError.NoAbiDecoder);
} }
@ -99,7 +112,8 @@ export class ContractWrapper {
return logWithDecodedArgs; return logWithDecodedArgs;
} }
protected async _instantiateContractIfExistsAsync( protected async _instantiateContractIfExistsAsync(
artifact: Artifact, addressIfExists?: string, artifact: Artifact,
addressIfExists?: string,
): Promise<Web3.ContractInstance> { ): Promise<Web3.ContractInstance> {
let contractAddress: string; let contractAddress: string;
if (_.isUndefined(addressIfExists)) { if (_.isUndefined(addressIfExists)) {
@ -114,9 +128,7 @@ export class ContractWrapper {
if (!doesContractExist) { if (!doesContractExist) {
throw new Error(CONTRACT_NAME_TO_NOT_FOUND_ERROR[artifact.contract_name]); throw new Error(CONTRACT_NAME_TO_NOT_FOUND_ERROR[artifact.contract_name]);
} }
const contractInstance = this._web3Wrapper.getContractInstance( const contractInstance = this._web3Wrapper.getContractInstance(artifact.abi, contractAddress);
artifact.abi, contractAddress,
);
return contractInstance; return contractInstance;
} }
protected _getContractAddress(artifact: Artifact, addressIfExists?: string): string { protected _getContractAddress(artifact: Artifact, addressIfExists?: string): string {
@ -153,7 +165,8 @@ export class ContractWrapper {
const catchAllLogFilter = {}; const catchAllLogFilter = {};
this._blockAndLogStreamerIfExists.addLogFilter(catchAllLogFilter); this._blockAndLogStreamerIfExists.addLogFilter(catchAllLogFilter);
this._blockAndLogStreamInterval = intervalUtils.setAsyncExcludingInterval( this._blockAndLogStreamInterval = intervalUtils.setAsyncExcludingInterval(
this._reconcileBlockAsync.bind(this), constants.DEFAULT_BLOCK_POLLING_INTERVAL, this._reconcileBlockAsync.bind(this),
constants.DEFAULT_BLOCK_POLLING_INTERVAL,
); );
let isRemoved = false; let isRemoved = false;
this._onLogAddedSubscriptionToken = this._blockAndLogStreamerIfExists.subscribeToOnLogAdded( this._onLogAddedSubscriptionToken = this._blockAndLogStreamerIfExists.subscribeToOnLogAdded(
@ -179,7 +192,7 @@ export class ContractWrapper {
// We need to coerce to Block type cause Web3.Block includes types for mempool blocks // We need to coerce to Block type cause Web3.Block includes types for mempool blocks
if (!_.isUndefined(this._blockAndLogStreamerIfExists)) { if (!_.isUndefined(this._blockAndLogStreamerIfExists)) {
// If we clear the interval while fetching the block - this._blockAndLogStreamer will be undefined // If we clear the interval while fetching the block - this._blockAndLogStreamer will be undefined
await this._blockAndLogStreamerIfExists.reconcileNewBlock(latestBlock as any as Block); await this._blockAndLogStreamerIfExists.reconcileNewBlock((latestBlock as any) as Block);
} }
} catch (err) { } catch (err) {
const filterTokens = _.keys(this._filterCallbacks); const filterTokens = _.keys(this._filterCallbacks);

View File

@ -26,7 +26,9 @@ import {TokenWrapper} from './token_wrapper';
* The caller can convert ETH into the equivalent number of wrapped ETH ERC20 tokens and back. * The caller can convert ETH into the equivalent number of wrapped ETH ERC20 tokens and back.
*/ */
export class EtherTokenWrapper extends ContractWrapper { export class EtherTokenWrapper extends ContractWrapper {
private _etherTokenContractsByAddress: {[address: string]: EtherTokenContract} = {}; private _etherTokenContractsByAddress: {
[address: string]: EtherTokenContract;
} = {};
private _tokenWrapper: TokenWrapper; private _tokenWrapper: TokenWrapper;
constructor(web3Wrapper: Web3Wrapper, networkId: number, abiDecoder: AbiDecoder, tokenWrapper: TokenWrapper) { constructor(web3Wrapper: Web3Wrapper, networkId: number, abiDecoder: AbiDecoder, tokenWrapper: TokenWrapper) {
super(web3Wrapper, networkId, abiDecoder); super(web3Wrapper, networkId, abiDecoder);
@ -43,7 +45,10 @@ export class EtherTokenWrapper extends ContractWrapper {
* @return Transaction hash. * @return Transaction hash.
*/ */
public async depositAsync( public async depositAsync(
etherTokenAddress: string, amountInWei: BigNumber, depositor: string, txOpts: TransactionOpts = {}, etherTokenAddress: string,
amountInWei: BigNumber,
depositor: string,
txOpts: TransactionOpts = {},
): Promise<string> { ): Promise<string> {
assert.isValidBaseUnitAmount('amountInWei', amountInWei); assert.isValidBaseUnitAmount('amountInWei', amountInWei);
await assert.isSenderAddressAsync('depositor', depositor, this._web3Wrapper); await assert.isSenderAddressAsync('depositor', depositor, this._web3Wrapper);
@ -70,7 +75,10 @@ export class EtherTokenWrapper extends ContractWrapper {
* @return Transaction hash. * @return Transaction hash.
*/ */
public async withdrawAsync( public async withdrawAsync(
etherTokenAddress: string, amountInWei: BigNumber, withdrawer: string, txOpts: TransactionOpts = {}, etherTokenAddress: string,
amountInWei: BigNumber,
withdrawer: string,
txOpts: TransactionOpts = {},
): Promise<string> { ): Promise<string> {
assert.isValidBaseUnitAmount('amountInWei', amountInWei); assert.isValidBaseUnitAmount('amountInWei', amountInWei);
await assert.isSenderAddressAsync('withdrawer', withdrawer, this._web3Wrapper); await assert.isSenderAddressAsync('withdrawer', withdrawer, this._web3Wrapper);
@ -96,14 +104,21 @@ export class EtherTokenWrapper extends ContractWrapper {
* @return Array of logs that match the parameters * @return Array of logs that match the parameters
*/ */
public async getLogsAsync<ArgsType extends EtherTokenContractEventArgs>( public async getLogsAsync<ArgsType extends EtherTokenContractEventArgs>(
etherTokenAddress: string, eventName: EtherTokenEvents, blockRange: BlockRange, etherTokenAddress: string,
indexFilterValues: IndexedFilterValues): Promise<Array<LogWithDecodedArgs<ArgsType>>> { eventName: EtherTokenEvents,
blockRange: BlockRange,
indexFilterValues: IndexedFilterValues,
): Promise<Array<LogWithDecodedArgs<ArgsType>>> {
assert.isETHAddressHex('etherTokenAddress', etherTokenAddress); assert.isETHAddressHex('etherTokenAddress', etherTokenAddress);
assert.doesBelongToStringEnum('eventName', eventName, EtherTokenEvents); assert.doesBelongToStringEnum('eventName', eventName, EtherTokenEvents);
assert.doesConformToSchema('blockRange', blockRange, schemas.blockRangeSchema); assert.doesConformToSchema('blockRange', blockRange, schemas.blockRangeSchema);
assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema); assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema);
const logs = await this._getLogsAsync<ArgsType>( const logs = await this._getLogsAsync<ArgsType>(
etherTokenAddress, eventName, blockRange, indexFilterValues, artifacts.EtherTokenArtifact.abi, etherTokenAddress,
eventName,
blockRange,
indexFilterValues,
artifacts.EtherTokenArtifact.abi,
); );
return logs; return logs;
} }
@ -117,14 +132,21 @@ export class EtherTokenWrapper extends ContractWrapper {
* @return Subscription token used later to unsubscribe * @return Subscription token used later to unsubscribe
*/ */
public subscribe<ArgsType extends EtherTokenContractEventArgs>( public subscribe<ArgsType extends EtherTokenContractEventArgs>(
etherTokenAddress: string, eventName: EtherTokenEvents, indexFilterValues: IndexedFilterValues, etherTokenAddress: string,
callback: EventCallback<ArgsType>): string { eventName: EtherTokenEvents,
indexFilterValues: IndexedFilterValues,
callback: EventCallback<ArgsType>,
): string {
assert.isETHAddressHex('etherTokenAddress', etherTokenAddress); assert.isETHAddressHex('etherTokenAddress', etherTokenAddress);
assert.doesBelongToStringEnum('eventName', eventName, EtherTokenEvents); assert.doesBelongToStringEnum('eventName', eventName, EtherTokenEvents);
assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema); assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema);
assert.isFunction('callback', callback); assert.isFunction('callback', callback);
const subscriptionToken = this._subscribe<ArgsType>( const subscriptionToken = this._subscribe<ArgsType>(
etherTokenAddress, eventName, indexFilterValues, artifacts.EtherTokenArtifact.abi, callback, etherTokenAddress,
eventName,
indexFilterValues,
artifacts.EtherTokenArtifact.abi,
callback,
); );
return subscriptionToken; return subscriptionToken;
} }
@ -151,7 +173,8 @@ export class EtherTokenWrapper extends ContractWrapper {
return etherTokenContract; return etherTokenContract;
} }
const web3ContractInstance = await this._instantiateContractIfExistsAsync( const web3ContractInstance = await this._instantiateContractIfExistsAsync(
artifacts.EtherTokenArtifact, etherTokenAddress, artifacts.EtherTokenArtifact,
etherTokenAddress,
); );
const contractInstance = new EtherTokenContract(web3ContractInstance, this._web3Wrapper.getContractDefaults()); const contractInstance = new EtherTokenContract(web3ContractInstance, this._web3Wrapper.getContractDefaults());
etherTokenContract = contractInstance; etherTokenContract = contractInstance;

View File

@ -81,8 +81,13 @@ export class ExchangeWrapper extends ContractWrapper {
]; ];
return [orderAddresses, orderValues]; return [orderAddresses, orderValues];
} }
constructor(web3Wrapper: Web3Wrapper, networkId: number, abiDecoder: AbiDecoder, constructor(
tokenWrapper: TokenWrapper, contractAddressIfExists?: string) { web3Wrapper: Web3Wrapper,
networkId: number,
abiDecoder: AbiDecoder,
tokenWrapper: TokenWrapper,
contractAddressIfExists?: string,
) {
super(web3Wrapper, networkId, abiDecoder); super(web3Wrapper, networkId, abiDecoder);
this._tokenWrapper = tokenWrapper; this._tokenWrapper = tokenWrapper;
this._orderValidationUtils = new OrderValidationUtils(this); this._orderValidationUtils = new OrderValidationUtils(this);
@ -97,14 +102,14 @@ export class ExchangeWrapper extends ContractWrapper {
* @param methodOpts Optional arguments this method accepts. * @param methodOpts Optional arguments this method accepts.
* @return The amount of the order (in taker tokens) that has either been filled or cancelled. * @return The amount of the order (in taker tokens) that has either been filled or cancelled.
*/ */
public async getUnavailableTakerAmountAsync(orderHash: string, public async getUnavailableTakerAmountAsync(orderHash: string, methodOpts?: MethodOpts): Promise<BigNumber> {
methodOpts?: MethodOpts): Promise<BigNumber> {
assert.doesConformToSchema('orderHash', orderHash, schemas.orderHashSchema); assert.doesConformToSchema('orderHash', orderHash, schemas.orderHashSchema);
const exchangeContract = await this._getExchangeContractAsync(); const exchangeContract = await this._getExchangeContractAsync();
const defaultBlock = _.isUndefined(methodOpts) ? undefined : methodOpts.defaultBlock; const defaultBlock = _.isUndefined(methodOpts) ? undefined : methodOpts.defaultBlock;
let unavailableTakerTokenAmount = await exchangeContract.getUnavailableTakerTokenAmount.callAsync( let unavailableTakerTokenAmount = await exchangeContract.getUnavailableTakerTokenAmount.callAsync(
orderHash, defaultBlock, orderHash,
defaultBlock,
); );
// Wrap BigNumbers returned from web3 with our own (later) version of BigNumber // Wrap BigNumbers returned from web3 with our own (later) version of BigNumber
unavailableTakerTokenAmount = new BigNumber(unavailableTakerTokenAmount); unavailableTakerTokenAmount = new BigNumber(unavailableTakerTokenAmount);
@ -163,24 +168,32 @@ export class ExchangeWrapper extends ContractWrapper {
* @return Transaction hash. * @return Transaction hash.
*/ */
@decorators.asyncZeroExErrorHandler @decorators.asyncZeroExErrorHandler
public async fillOrderAsync(signedOrder: SignedOrder, fillTakerTokenAmount: BigNumber, public async fillOrderAsync(
signedOrder: SignedOrder,
fillTakerTokenAmount: BigNumber,
shouldThrowOnInsufficientBalanceOrAllowance: boolean, shouldThrowOnInsufficientBalanceOrAllowance: boolean,
takerAddress: string, takerAddress: string,
orderTransactionOpts: OrderTransactionOpts = {}): Promise<string> { orderTransactionOpts: OrderTransactionOpts = {},
): Promise<string> {
assert.doesConformToSchema('signedOrder', signedOrder, schemas.signedOrderSchema); assert.doesConformToSchema('signedOrder', signedOrder, schemas.signedOrderSchema);
assert.isValidBaseUnitAmount('fillTakerTokenAmount', fillTakerTokenAmount); assert.isValidBaseUnitAmount('fillTakerTokenAmount', fillTakerTokenAmount);
assert.isBoolean('shouldThrowOnInsufficientBalanceOrAllowance', shouldThrowOnInsufficientBalanceOrAllowance); assert.isBoolean('shouldThrowOnInsufficientBalanceOrAllowance', shouldThrowOnInsufficientBalanceOrAllowance);
await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper); await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper);
const exchangeInstance = await this._getExchangeContractAsync(); const exchangeInstance = await this._getExchangeContractAsync();
const shouldValidate = _.isUndefined(orderTransactionOpts.shouldValidate) ? const shouldValidate = _.isUndefined(orderTransactionOpts.shouldValidate)
SHOULD_VALIDATE_BY_DEFAULT : ? SHOULD_VALIDATE_BY_DEFAULT
orderTransactionOpts.shouldValidate; : orderTransactionOpts.shouldValidate;
if (shouldValidate) { if (shouldValidate) {
const zrxTokenAddress = this.getZRXTokenAddress(); const zrxTokenAddress = this.getZRXTokenAddress();
const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest); const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest);
await this._orderValidationUtils.validateFillOrderThrowIfInvalidAsync( await this._orderValidationUtils.validateFillOrderThrowIfInvalidAsync(
exchangeTradeEmulator, signedOrder, fillTakerTokenAmount, takerAddress, zrxTokenAddress); exchangeTradeEmulator,
signedOrder,
fillTakerTokenAmount,
takerAddress,
zrxTokenAddress,
);
} }
const [orderAddresses, orderValues] = ExchangeWrapper._getOrderAddressesAndValues(signedOrder); const [orderAddresses, orderValues] = ExchangeWrapper._getOrderAddressesAndValues(signedOrder);
@ -219,30 +232,42 @@ export class ExchangeWrapper extends ContractWrapper {
* @return Transaction hash. * @return Transaction hash.
*/ */
@decorators.asyncZeroExErrorHandler @decorators.asyncZeroExErrorHandler
public async fillOrdersUpToAsync(signedOrders: SignedOrder[], fillTakerTokenAmount: BigNumber, public async fillOrdersUpToAsync(
signedOrders: SignedOrder[],
fillTakerTokenAmount: BigNumber,
shouldThrowOnInsufficientBalanceOrAllowance: boolean, shouldThrowOnInsufficientBalanceOrAllowance: boolean,
takerAddress: string, takerAddress: string,
orderTransactionOpts: OrderTransactionOpts = {}): Promise<string> { orderTransactionOpts: OrderTransactionOpts = {},
): Promise<string> {
assert.doesConformToSchema('signedOrders', signedOrders, schemas.signedOrdersSchema); assert.doesConformToSchema('signedOrders', signedOrders, schemas.signedOrdersSchema);
const takerTokenAddresses = _.map(signedOrders, signedOrder => signedOrder.takerTokenAddress); const takerTokenAddresses = _.map(signedOrders, signedOrder => signedOrder.takerTokenAddress);
assert.hasAtMostOneUniqueValue(takerTokenAddresses, assert.hasAtMostOneUniqueValue(
ExchangeContractErrs.MultipleTakerTokensInFillUpToDisallowed); takerTokenAddresses,
ExchangeContractErrs.MultipleTakerTokensInFillUpToDisallowed,
);
const exchangeContractAddresses = _.map(signedOrders, signedOrder => signedOrder.exchangeContractAddress); const exchangeContractAddresses = _.map(signedOrders, signedOrder => signedOrder.exchangeContractAddress);
assert.hasAtMostOneUniqueValue(exchangeContractAddresses, assert.hasAtMostOneUniqueValue(
ExchangeContractErrs.BatchOrdersMustHaveSameExchangeAddress); exchangeContractAddresses,
ExchangeContractErrs.BatchOrdersMustHaveSameExchangeAddress,
);
assert.isValidBaseUnitAmount('fillTakerTokenAmount', fillTakerTokenAmount); assert.isValidBaseUnitAmount('fillTakerTokenAmount', fillTakerTokenAmount);
assert.isBoolean('shouldThrowOnInsufficientBalanceOrAllowance', shouldThrowOnInsufficientBalanceOrAllowance); assert.isBoolean('shouldThrowOnInsufficientBalanceOrAllowance', shouldThrowOnInsufficientBalanceOrAllowance);
await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper); await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper);
const shouldValidate = _.isUndefined(orderTransactionOpts.shouldValidate) ? const shouldValidate = _.isUndefined(orderTransactionOpts.shouldValidate)
SHOULD_VALIDATE_BY_DEFAULT : ? SHOULD_VALIDATE_BY_DEFAULT
orderTransactionOpts.shouldValidate; : orderTransactionOpts.shouldValidate;
if (shouldValidate) { if (shouldValidate) {
const zrxTokenAddress = this.getZRXTokenAddress(); const zrxTokenAddress = this.getZRXTokenAddress();
const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest); const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest);
for (const signedOrder of signedOrders) { for (const signedOrder of signedOrders) {
await this._orderValidationUtils.validateFillOrderThrowIfInvalidAsync( await this._orderValidationUtils.validateFillOrderThrowIfInvalidAsync(
exchangeTradeEmulator, signedOrder, fillTakerTokenAmount, takerAddress, zrxTokenAddress); exchangeTradeEmulator,
signedOrder,
fillTakerTokenAmount,
takerAddress,
zrxTokenAddress,
);
} }
} }
@ -300,29 +325,36 @@ export class ExchangeWrapper extends ContractWrapper {
* @return Transaction hash. * @return Transaction hash.
*/ */
@decorators.asyncZeroExErrorHandler @decorators.asyncZeroExErrorHandler
public async batchFillOrdersAsync(orderFillRequests: OrderFillRequest[], public async batchFillOrdersAsync(
orderFillRequests: OrderFillRequest[],
shouldThrowOnInsufficientBalanceOrAllowance: boolean, shouldThrowOnInsufficientBalanceOrAllowance: boolean,
takerAddress: string, takerAddress: string,
orderTransactionOpts: OrderTransactionOpts = {}): Promise<string> { orderTransactionOpts: OrderTransactionOpts = {},
): Promise<string> {
assert.doesConformToSchema('orderFillRequests', orderFillRequests, schemas.orderFillRequestsSchema); assert.doesConformToSchema('orderFillRequests', orderFillRequests, schemas.orderFillRequestsSchema);
const exchangeContractAddresses = _.map( const exchangeContractAddresses = _.map(
orderFillRequests, orderFillRequests,
orderFillRequest => orderFillRequest.signedOrder.exchangeContractAddress, orderFillRequest => orderFillRequest.signedOrder.exchangeContractAddress,
); );
assert.hasAtMostOneUniqueValue(exchangeContractAddresses, assert.hasAtMostOneUniqueValue(
ExchangeContractErrs.BatchOrdersMustHaveSameExchangeAddress); exchangeContractAddresses,
ExchangeContractErrs.BatchOrdersMustHaveSameExchangeAddress,
);
assert.isBoolean('shouldThrowOnInsufficientBalanceOrAllowance', shouldThrowOnInsufficientBalanceOrAllowance); assert.isBoolean('shouldThrowOnInsufficientBalanceOrAllowance', shouldThrowOnInsufficientBalanceOrAllowance);
await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper); await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper);
const shouldValidate = _.isUndefined(orderTransactionOpts.shouldValidate) ? const shouldValidate = _.isUndefined(orderTransactionOpts.shouldValidate)
SHOULD_VALIDATE_BY_DEFAULT : ? SHOULD_VALIDATE_BY_DEFAULT
orderTransactionOpts.shouldValidate; : orderTransactionOpts.shouldValidate;
if (shouldValidate) { if (shouldValidate) {
const zrxTokenAddress = this.getZRXTokenAddress(); const zrxTokenAddress = this.getZRXTokenAddress();
const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest); const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest);
for (const orderFillRequest of orderFillRequests) { for (const orderFillRequest of orderFillRequests) {
await this._orderValidationUtils.validateFillOrderThrowIfInvalidAsync( await this._orderValidationUtils.validateFillOrderThrowIfInvalidAsync(
exchangeTradeEmulator, orderFillRequest.signedOrder, orderFillRequest.takerTokenFillAmount, exchangeTradeEmulator,
takerAddress, zrxTokenAddress, orderFillRequest.signedOrder,
orderFillRequest.takerTokenFillAmount,
takerAddress,
zrxTokenAddress,
); );
} }
} }
@ -373,23 +405,31 @@ export class ExchangeWrapper extends ContractWrapper {
* @return Transaction hash. * @return Transaction hash.
*/ */
@decorators.asyncZeroExErrorHandler @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> {
assert.doesConformToSchema('signedOrder', signedOrder, schemas.signedOrderSchema); assert.doesConformToSchema('signedOrder', signedOrder, schemas.signedOrderSchema);
assert.isValidBaseUnitAmount('fillTakerTokenAmount', fillTakerTokenAmount); assert.isValidBaseUnitAmount('fillTakerTokenAmount', fillTakerTokenAmount);
await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper); await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper);
const exchangeInstance = await this._getExchangeContractAsync(); const exchangeInstance = await this._getExchangeContractAsync();
const shouldValidate = _.isUndefined(orderTransactionOpts.shouldValidate) ? const shouldValidate = _.isUndefined(orderTransactionOpts.shouldValidate)
SHOULD_VALIDATE_BY_DEFAULT : ? SHOULD_VALIDATE_BY_DEFAULT
orderTransactionOpts.shouldValidate; : orderTransactionOpts.shouldValidate;
if (shouldValidate) { if (shouldValidate) {
const zrxTokenAddress = this.getZRXTokenAddress(); const zrxTokenAddress = this.getZRXTokenAddress();
const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest); const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest);
await this._orderValidationUtils.validateFillOrKillOrderThrowIfInvalidAsync( await this._orderValidationUtils.validateFillOrKillOrderThrowIfInvalidAsync(
exchangeTradeEmulator, signedOrder, fillTakerTokenAmount, takerAddress, zrxTokenAddress); exchangeTradeEmulator,
signedOrder,
fillTakerTokenAmount,
takerAddress,
zrxTokenAddress,
);
} }
const [orderAddresses, orderValues] = ExchangeWrapper._getOrderAddressesAndValues(signedOrder); const [orderAddresses, orderValues] = ExchangeWrapper._getOrderAddressesAndValues(signedOrder);
@ -418,33 +458,39 @@ export class ExchangeWrapper extends ContractWrapper {
* @return Transaction hash. * @return Transaction hash.
*/ */
@decorators.asyncZeroExErrorHandler @decorators.asyncZeroExErrorHandler
public async batchFillOrKillAsync(orderFillRequests: OrderFillRequest[], public async batchFillOrKillAsync(
orderFillRequests: OrderFillRequest[],
takerAddress: string, takerAddress: string,
orderTransactionOpts: OrderTransactionOpts = {}): Promise<string> { orderTransactionOpts: OrderTransactionOpts = {},
assert.doesConformToSchema('orderFillRequests', orderFillRequests, ): Promise<string> {
schemas.orderFillRequestsSchema); assert.doesConformToSchema('orderFillRequests', orderFillRequests, schemas.orderFillRequestsSchema);
const exchangeContractAddresses = _.map( const exchangeContractAddresses = _.map(
orderFillRequests, orderFillRequests,
orderFillRequest => orderFillRequest.signedOrder.exchangeContractAddress, orderFillRequest => orderFillRequest.signedOrder.exchangeContractAddress,
); );
assert.hasAtMostOneUniqueValue(exchangeContractAddresses, assert.hasAtMostOneUniqueValue(
ExchangeContractErrs.BatchOrdersMustHaveSameExchangeAddress); exchangeContractAddresses,
ExchangeContractErrs.BatchOrdersMustHaveSameExchangeAddress,
);
await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper); await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper);
if (_.isEmpty(orderFillRequests)) { if (_.isEmpty(orderFillRequests)) {
throw new Error(ExchangeContractErrs.BatchOrdersMustHaveAtLeastOneItem); throw new Error(ExchangeContractErrs.BatchOrdersMustHaveAtLeastOneItem);
} }
const exchangeInstance = await this._getExchangeContractAsync(); const exchangeInstance = await this._getExchangeContractAsync();
const shouldValidate = _.isUndefined(orderTransactionOpts.shouldValidate) ? const shouldValidate = _.isUndefined(orderTransactionOpts.shouldValidate)
SHOULD_VALIDATE_BY_DEFAULT : ? SHOULD_VALIDATE_BY_DEFAULT
orderTransactionOpts.shouldValidate; : orderTransactionOpts.shouldValidate;
if (shouldValidate) { if (shouldValidate) {
const zrxTokenAddress = this.getZRXTokenAddress(); const zrxTokenAddress = this.getZRXTokenAddress();
const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest); const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest);
for (const orderFillRequest of orderFillRequests) { for (const orderFillRequest of orderFillRequests) {
await this._orderValidationUtils.validateFillOrKillOrderThrowIfInvalidAsync( await this._orderValidationUtils.validateFillOrKillOrderThrowIfInvalidAsync(
exchangeTradeEmulator, orderFillRequest.signedOrder, orderFillRequest.takerTokenFillAmount, exchangeTradeEmulator,
takerAddress, zrxTokenAddress, orderFillRequest.signedOrder,
orderFillRequest.takerTokenFillAmount,
takerAddress,
zrxTokenAddress,
); );
} }
} }
@ -460,8 +506,9 @@ export class ExchangeWrapper extends ContractWrapper {
}); });
// We use _.unzip<any> because _.unzip doesn't type check if values have different types :'( // We use _.unzip<any> because _.unzip doesn't type check if values have different types :'(
const [orderAddresses, orderValues, fillTakerTokenAmounts, vParams, rParams, sParams] = const [orderAddresses, orderValues, fillTakerTokenAmounts, vParams, rParams, sParams] = _.unzip<any>(
_.unzip<any>(orderAddressesValuesAndTakerTokenFillAmounts); orderAddressesValuesAndTakerTokenFillAmounts,
);
const txHash = await exchangeInstance.batchFillOrKillOrders.sendTransactionAsync( const txHash = await exchangeInstance.batchFillOrKillOrders.sendTransactionAsync(
orderAddresses, orderAddresses,
orderValues, orderValues,
@ -486,23 +533,28 @@ export class ExchangeWrapper extends ContractWrapper {
* @return Transaction hash. * @return Transaction hash.
*/ */
@decorators.asyncZeroExErrorHandler @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> {
assert.doesConformToSchema('order', order, schemas.orderSchema); assert.doesConformToSchema('order', order, schemas.orderSchema);
assert.isValidBaseUnitAmount('takerTokenCancelAmount', cancelTakerTokenAmount); assert.isValidBaseUnitAmount('takerTokenCancelAmount', cancelTakerTokenAmount);
await assert.isSenderAddressAsync('order.maker', order.maker, this._web3Wrapper); await assert.isSenderAddressAsync('order.maker', order.maker, this._web3Wrapper);
const exchangeInstance = await this._getExchangeContractAsync(); const exchangeInstance = await this._getExchangeContractAsync();
const shouldValidate = _.isUndefined(orderTransactionOpts.shouldValidate) ? const shouldValidate = _.isUndefined(orderTransactionOpts.shouldValidate)
SHOULD_VALIDATE_BY_DEFAULT : ? SHOULD_VALIDATE_BY_DEFAULT
orderTransactionOpts.shouldValidate; : orderTransactionOpts.shouldValidate;
if (shouldValidate) { if (shouldValidate) {
const orderHash = utils.getOrderHashHex(order); const orderHash = utils.getOrderHashHex(order);
const unavailableTakerTokenAmount = await this.getUnavailableTakerAmountAsync(orderHash); const unavailableTakerTokenAmount = await this.getUnavailableTakerAmountAsync(orderHash);
OrderValidationUtils.validateCancelOrderThrowIfInvalid( OrderValidationUtils.validateCancelOrderThrowIfInvalid(
order, cancelTakerTokenAmount, unavailableTakerTokenAmount); order,
cancelTakerTokenAmount,
unavailableTakerTokenAmount,
);
} }
const [orderAddresses, orderValues] = ExchangeWrapper._getOrderAddressesAndValues(order); const [orderAddresses, orderValues] = ExchangeWrapper._getOrderAddressesAndValues(order);
@ -527,33 +579,40 @@ export class ExchangeWrapper extends ContractWrapper {
* @return Transaction hash. * @return Transaction hash.
*/ */
@decorators.asyncZeroExErrorHandler @decorators.asyncZeroExErrorHandler
public async batchCancelOrdersAsync(orderCancellationRequests: OrderCancellationRequest[], public async batchCancelOrdersAsync(
orderTransactionOpts: OrderTransactionOpts = {}): Promise<string> { orderCancellationRequests: OrderCancellationRequest[],
assert.doesConformToSchema('orderCancellationRequests', orderCancellationRequests, orderTransactionOpts: OrderTransactionOpts = {},
schemas.orderCancellationRequestsSchema); ): Promise<string> {
assert.doesConformToSchema(
'orderCancellationRequests',
orderCancellationRequests,
schemas.orderCancellationRequestsSchema,
);
const exchangeContractAddresses = _.map( const exchangeContractAddresses = _.map(
orderCancellationRequests, orderCancellationRequests,
orderCancellationRequest => orderCancellationRequest.order.exchangeContractAddress, orderCancellationRequest => orderCancellationRequest.order.exchangeContractAddress,
); );
assert.hasAtMostOneUniqueValue(exchangeContractAddresses, assert.hasAtMostOneUniqueValue(
ExchangeContractErrs.BatchOrdersMustHaveSameExchangeAddress); exchangeContractAddresses,
ExchangeContractErrs.BatchOrdersMustHaveSameExchangeAddress,
);
const makers = _.map(orderCancellationRequests, cancellationRequest => cancellationRequest.order.maker); const makers = _.map(orderCancellationRequests, cancellationRequest => cancellationRequest.order.maker);
assert.hasAtMostOneUniqueValue(makers, ExchangeContractErrs.MultipleMakersInSingleCancelBatchDisallowed); assert.hasAtMostOneUniqueValue(makers, ExchangeContractErrs.MultipleMakersInSingleCancelBatchDisallowed);
const maker = makers[0]; const maker = makers[0];
await assert.isSenderAddressAsync('maker', maker, this._web3Wrapper); await assert.isSenderAddressAsync('maker', maker, this._web3Wrapper);
const shouldValidate = _.isUndefined(orderTransactionOpts.shouldValidate) ? const shouldValidate = _.isUndefined(orderTransactionOpts.shouldValidate)
SHOULD_VALIDATE_BY_DEFAULT : ? SHOULD_VALIDATE_BY_DEFAULT
orderTransactionOpts.shouldValidate; : orderTransactionOpts.shouldValidate;
if (shouldValidate) { if (shouldValidate) {
for (const orderCancellationRequest of orderCancellationRequests) { for (const orderCancellationRequest of orderCancellationRequests) {
const orderHash = utils.getOrderHashHex(orderCancellationRequest.order); const orderHash = utils.getOrderHashHex(orderCancellationRequest.order);
const unavailableTakerTokenAmount = await this.getUnavailableTakerAmountAsync(orderHash); const unavailableTakerTokenAmount = await this.getUnavailableTakerAmountAsync(orderHash);
OrderValidationUtils.validateCancelOrderThrowIfInvalid( OrderValidationUtils.validateCancelOrderThrowIfInvalid(
orderCancellationRequest.order, orderCancellationRequest.takerTokenCancelAmount, orderCancellationRequest.order,
orderCancellationRequest.takerTokenCancelAmount,
unavailableTakerTokenAmount, unavailableTakerTokenAmount,
); );
} }
} }
if (_.isEmpty(orderCancellationRequests)) { if (_.isEmpty(orderCancellationRequests)) {
throw new Error(ExchangeContractErrs.BatchOrdersMustHaveAtLeastOneItem); throw new Error(ExchangeContractErrs.BatchOrdersMustHaveAtLeastOneItem);
@ -566,8 +625,9 @@ export class ExchangeWrapper extends ContractWrapper {
]; ];
}); });
// We use _.unzip<any> because _.unzip doesn't type check if values have different types :'( // We use _.unzip<any> because _.unzip doesn't type check if values have different types :'(
const [orderAddresses, orderValues, cancelTakerTokenAmounts] = const [orderAddresses, orderValues, cancelTakerTokenAmounts] = _.unzip<any>(
_.unzip<any>(orderAddressesValuesAndTakerTokenCancelAmounts); orderAddressesValuesAndTakerTokenCancelAmounts,
);
const txHash = await exchangeInstance.batchCancelOrders.sendTransactionAsync( const txHash = await exchangeInstance.batchCancelOrders.sendTransactionAsync(
orderAddresses, orderAddresses,
orderValues, orderValues,
@ -589,14 +649,20 @@ export class ExchangeWrapper extends ContractWrapper {
* @return Subscription token used later to unsubscribe * @return Subscription token used later to unsubscribe
*/ */
public subscribe<ArgsType extends ExchangeContractEventArgs>( public subscribe<ArgsType extends ExchangeContractEventArgs>(
eventName: ExchangeEvents, indexFilterValues: IndexedFilterValues, eventName: ExchangeEvents,
callback: EventCallback<ArgsType>): string { indexFilterValues: IndexedFilterValues,
callback: EventCallback<ArgsType>,
): string {
assert.doesBelongToStringEnum('eventName', eventName, ExchangeEvents); assert.doesBelongToStringEnum('eventName', eventName, ExchangeEvents);
assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema); assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema);
assert.isFunction('callback', callback); assert.isFunction('callback', callback);
const exchangeContractAddress = this.getContractAddress(); const exchangeContractAddress = this.getContractAddress();
const subscriptionToken = this._subscribe<ArgsType>( const subscriptionToken = this._subscribe<ArgsType>(
exchangeContractAddress, eventName, indexFilterValues, artifacts.ExchangeArtifact.abi, callback, exchangeContractAddress,
eventName,
indexFilterValues,
artifacts.ExchangeArtifact.abi,
callback,
); );
return subscriptionToken; return subscriptionToken;
} }
@ -622,14 +688,20 @@ export class ExchangeWrapper extends ContractWrapper {
* @return Array of logs that match the parameters * @return Array of logs that match the parameters
*/ */
public async getLogsAsync<ArgsType extends ExchangeContractEventArgs>( public async getLogsAsync<ArgsType extends ExchangeContractEventArgs>(
eventName: ExchangeEvents, blockRange: BlockRange, indexFilterValues: IndexedFilterValues, eventName: ExchangeEvents,
blockRange: BlockRange,
indexFilterValues: IndexedFilterValues,
): Promise<Array<LogWithDecodedArgs<ArgsType>>> { ): Promise<Array<LogWithDecodedArgs<ArgsType>>> {
assert.doesBelongToStringEnum('eventName', eventName, ExchangeEvents); assert.doesBelongToStringEnum('eventName', eventName, ExchangeEvents);
assert.doesConformToSchema('blockRange', blockRange, schemas.blockRangeSchema); assert.doesConformToSchema('blockRange', blockRange, schemas.blockRangeSchema);
assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema); assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema);
const exchangeContractAddress = this.getContractAddress(); const exchangeContractAddress = this.getContractAddress();
const logs = await this._getLogsAsync<ArgsType>( const logs = await this._getLogsAsync<ArgsType>(
exchangeContractAddress, eventName, blockRange, indexFilterValues, artifacts.ExchangeArtifact.abi, exchangeContractAddress,
eventName,
blockRange,
indexFilterValues,
artifacts.ExchangeArtifact.abi,
); );
return logs; return logs;
} }
@ -652,14 +724,18 @@ export class ExchangeWrapper extends ContractWrapper {
* to validate for. * to validate for.
*/ */
public async validateOrderFillableOrThrowAsync( public async validateOrderFillableOrThrowAsync(
signedOrder: SignedOrder, opts?: ValidateOrderFillableOpts, signedOrder: SignedOrder,
opts?: ValidateOrderFillableOpts,
): Promise<void> { ): Promise<void> {
assert.doesConformToSchema('signedOrder', signedOrder, schemas.signedOrderSchema); assert.doesConformToSchema('signedOrder', signedOrder, schemas.signedOrderSchema);
const zrxTokenAddress = this.getZRXTokenAddress(); const zrxTokenAddress = this.getZRXTokenAddress();
const expectedFillTakerTokenAmount = !_.isUndefined(opts) ? opts.expectedFillTakerTokenAmount : undefined; const expectedFillTakerTokenAmount = !_.isUndefined(opts) ? opts.expectedFillTakerTokenAmount : undefined;
const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest); const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest);
await this._orderValidationUtils.validateOrderFillableOrThrowAsync( await this._orderValidationUtils.validateOrderFillableOrThrowAsync(
exchangeTradeEmulator, signedOrder, zrxTokenAddress, expectedFillTakerTokenAmount, exchangeTradeEmulator,
signedOrder,
zrxTokenAddress,
expectedFillTakerTokenAmount,
); );
} }
/** /**
@ -670,16 +746,23 @@ export class ExchangeWrapper extends ContractWrapper {
* @param takerAddress The user Ethereum address who would like to fill this order. * @param takerAddress The user Ethereum address who would like to fill this order.
* Must be available via the supplied Web3.Provider passed to 0x.js. * Must be available via the supplied Web3.Provider passed to 0x.js.
*/ */
public async validateFillOrderThrowIfInvalidAsync(signedOrder: SignedOrder, public async validateFillOrderThrowIfInvalidAsync(
signedOrder: SignedOrder,
fillTakerTokenAmount: BigNumber, fillTakerTokenAmount: BigNumber,
takerAddress: string): Promise<void> { takerAddress: string,
): Promise<void> {
assert.doesConformToSchema('signedOrder', signedOrder, schemas.signedOrderSchema); assert.doesConformToSchema('signedOrder', signedOrder, schemas.signedOrderSchema);
assert.isValidBaseUnitAmount('fillTakerTokenAmount', fillTakerTokenAmount); assert.isValidBaseUnitAmount('fillTakerTokenAmount', fillTakerTokenAmount);
await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper); await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper);
const zrxTokenAddress = this.getZRXTokenAddress(); const zrxTokenAddress = this.getZRXTokenAddress();
const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest); const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest);
await this._orderValidationUtils.validateFillOrderThrowIfInvalidAsync( await this._orderValidationUtils.validateFillOrderThrowIfInvalidAsync(
exchangeTradeEmulator, signedOrder, fillTakerTokenAmount, takerAddress, zrxTokenAddress); exchangeTradeEmulator,
signedOrder,
fillTakerTokenAmount,
takerAddress,
zrxTokenAddress,
);
} }
/** /**
* Checks if cancelling a given order will succeed and throws an informative error if it won't. * Checks if cancelling a given order will succeed and throws an informative error if it won't.
@ -688,13 +771,18 @@ export class ExchangeWrapper extends ContractWrapper {
* @param cancelTakerTokenAmount The amount (specified in taker tokens) that you would like to cancel. * @param cancelTakerTokenAmount The amount (specified in taker tokens) that you would like to cancel.
*/ */
public async validateCancelOrderThrowIfInvalidAsync( public async validateCancelOrderThrowIfInvalidAsync(
order: Order, cancelTakerTokenAmount: BigNumber): Promise<void> { order: Order,
cancelTakerTokenAmount: BigNumber,
): Promise<void> {
assert.doesConformToSchema('order', order, schemas.orderSchema); assert.doesConformToSchema('order', order, schemas.orderSchema);
assert.isValidBaseUnitAmount('cancelTakerTokenAmount', cancelTakerTokenAmount); assert.isValidBaseUnitAmount('cancelTakerTokenAmount', cancelTakerTokenAmount);
const orderHash = utils.getOrderHashHex(order); const orderHash = utils.getOrderHashHex(order);
const unavailableTakerTokenAmount = await this.getUnavailableTakerAmountAsync(orderHash); const unavailableTakerTokenAmount = await this.getUnavailableTakerAmountAsync(orderHash);
OrderValidationUtils.validateCancelOrderThrowIfInvalid( OrderValidationUtils.validateCancelOrderThrowIfInvalid(
order, cancelTakerTokenAmount, unavailableTakerTokenAmount); order,
cancelTakerTokenAmount,
unavailableTakerTokenAmount,
);
} }
/** /**
* Checks if calling fillOrKill on a given order will succeed and throws an informative error if it won't. * Checks if calling fillOrKill on a given order will succeed and throws an informative error if it won't.
@ -704,16 +792,23 @@ export class ExchangeWrapper extends ContractWrapper {
* @param takerAddress The user Ethereum address who would like to fill this order. * @param takerAddress The user Ethereum address who would like to fill this order.
* Must be available via the supplied Web3.Provider passed to 0x.js. * Must be available via the supplied Web3.Provider passed to 0x.js.
*/ */
public async validateFillOrKillOrderThrowIfInvalidAsync(signedOrder: SignedOrder, public async validateFillOrKillOrderThrowIfInvalidAsync(
signedOrder: SignedOrder,
fillTakerTokenAmount: BigNumber, fillTakerTokenAmount: BigNumber,
takerAddress: string): Promise<void> { takerAddress: string,
): Promise<void> {
assert.doesConformToSchema('signedOrder', signedOrder, schemas.signedOrderSchema); assert.doesConformToSchema('signedOrder', signedOrder, schemas.signedOrderSchema);
assert.isValidBaseUnitAmount('fillTakerTokenAmount', fillTakerTokenAmount); assert.isValidBaseUnitAmount('fillTakerTokenAmount', fillTakerTokenAmount);
await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper); await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper);
const zrxTokenAddress = this.getZRXTokenAddress(); const zrxTokenAddress = this.getZRXTokenAddress();
const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest); const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest);
await this._orderValidationUtils.validateFillOrKillOrderThrowIfInvalidAsync( await this._orderValidationUtils.validateFillOrKillOrderThrowIfInvalidAsync(
exchangeTradeEmulator, signedOrder, fillTakerTokenAmount, takerAddress, zrxTokenAddress); exchangeTradeEmulator,
signedOrder,
fillTakerTokenAmount,
takerAddress,
zrxTokenAddress,
);
} }
/** /**
* Checks if rounding error will be > 0.1% when computing makerTokenAmount by doing: * Checks if rounding error will be > 0.1% when computing makerTokenAmount by doing:
@ -724,15 +819,19 @@ export class ExchangeWrapper extends ContractWrapper {
* @param takerTokenAmount The order size on the taker side * @param takerTokenAmount The order size on the taker side
* @param makerTokenAmount The order size on the maker side * @param makerTokenAmount The order size on the maker side
*/ */
public async isRoundingErrorAsync(fillTakerTokenAmount: BigNumber, public async isRoundingErrorAsync(
fillTakerTokenAmount: BigNumber,
takerTokenAmount: BigNumber, takerTokenAmount: BigNumber,
makerTokenAmount: BigNumber): Promise<boolean> { makerTokenAmount: BigNumber,
): Promise<boolean> {
assert.isValidBaseUnitAmount('fillTakerTokenAmount', fillTakerTokenAmount); assert.isValidBaseUnitAmount('fillTakerTokenAmount', fillTakerTokenAmount);
assert.isValidBaseUnitAmount('takerTokenAmount', takerTokenAmount); assert.isValidBaseUnitAmount('takerTokenAmount', takerTokenAmount);
assert.isValidBaseUnitAmount('makerTokenAmount', makerTokenAmount); assert.isValidBaseUnitAmount('makerTokenAmount', makerTokenAmount);
const exchangeInstance = await this._getExchangeContractAsync(); const exchangeInstance = await this._getExchangeContractAsync();
const isRoundingError = await exchangeInstance.isRoundingError.callAsync( const isRoundingError = await exchangeInstance.isRoundingError.callAsync(
fillTakerTokenAmount, takerTokenAmount, makerTokenAmount, fillTakerTokenAmount,
takerTokenAmount,
makerTokenAmount,
); );
return isRoundingError; return isRoundingError;
} }
@ -756,17 +855,18 @@ export class ExchangeWrapper extends ContractWrapper {
* @return Address of ZRX token * @return Address of ZRX token
*/ */
public getZRXTokenAddress(): string { public getZRXTokenAddress(): string {
const contractAddress = this._getContractAddress( const contractAddress = this._getContractAddress(artifacts.ZRXArtifact, this._zrxContractAddressIfExists);
artifacts.ZRXArtifact, this._zrxContractAddressIfExists,
);
return contractAddress; return contractAddress;
} }
private _invalidateContractInstances(): void { private _invalidateContractInstances(): void {
this.unsubscribeAll(); this.unsubscribeAll();
delete this._exchangeContractIfExists; delete this._exchangeContractIfExists;
} }
private async _isValidSignatureUsingContractCallAsync(dataHex: string, ecSignature: ECSignature, private async _isValidSignatureUsingContractCallAsync(
signerAddressHex: string): Promise<boolean> { dataHex: string,
ecSignature: ECSignature,
signerAddressHex: string,
): Promise<boolean> {
assert.isHexString('dataHex', dataHex); assert.isHexString('dataHex', dataHex);
assert.doesConformToSchema('ecSignature', ecSignature, schemas.ecSignatureSchema); assert.doesConformToSchema('ecSignature', ecSignature, schemas.ecSignatureSchema);
assert.isETHAddressHex('signerAddressHex', signerAddressHex); assert.isETHAddressHex('signerAddressHex', signerAddressHex);
@ -793,7 +893,8 @@ export class ExchangeWrapper extends ContractWrapper {
return this._exchangeContractIfExists; return this._exchangeContractIfExists;
} }
const web3ContractInstance = await this._instantiateContractIfExistsAsync( const web3ContractInstance = await this._instantiateContractIfExistsAsync(
artifacts.ExchangeArtifact, this._contractAddressIfExists, artifacts.ExchangeArtifact,
this._contractAddressIfExists,
); );
const contractInstance = new ExchangeContract(web3ContractInstance, this._web3Wrapper.getContractDefaults()); const contractInstance = new ExchangeContract(web3ContractInstance, this._web3Wrapper.getContractDefaults());
this._exchangeContractIfExists = contractInstance; this._exchangeContractIfExists = contractInstance;

View File

@ -37,9 +37,8 @@ export class TokenRegistryWrapper extends ContractWrapper {
*/ */
public async getTokensAsync(): Promise<Token[]> { public async getTokensAsync(): Promise<Token[]> {
const addresses = await this.getTokenAddressesAsync(); const addresses = await this.getTokenAddressesAsync();
const tokenPromises: Array<Promise<Token|undefined>> = _.map( const tokenPromises: Array<Promise<Token | undefined>> = _.map(addresses, async (address: string) =>
addresses, this.getTokenIfExistsAsync(address),
async (address: string) => this.getTokenIfExistsAsync(address),
); );
const tokens = await Promise.all(tokenPromises); const tokens = await Promise.all(tokenPromises);
return tokens as Token[]; return tokens as Token[];
@ -104,7 +103,8 @@ export class TokenRegistryWrapper extends ContractWrapper {
*/ */
public getContractAddress(): string { public getContractAddress(): string {
const contractAddress = this._getContractAddress( const contractAddress = this._getContractAddress(
artifacts.TokenRegistryArtifact, this._contractAddressIfExists, artifacts.TokenRegistryArtifact,
this._contractAddressIfExists,
); );
return contractAddress; return contractAddress;
} }
@ -116,10 +116,12 @@ export class TokenRegistryWrapper extends ContractWrapper {
return this._tokenRegistryContractIfExists; return this._tokenRegistryContractIfExists;
} }
const web3ContractInstance = await this._instantiateContractIfExistsAsync( const web3ContractInstance = await this._instantiateContractIfExistsAsync(
artifacts.TokenRegistryArtifact, this._contractAddressIfExists, artifacts.TokenRegistryArtifact,
this._contractAddressIfExists,
); );
const contractInstance = new TokenRegistryContract( const contractInstance = new TokenRegistryContract(
web3ContractInstance, this._web3Wrapper.getContractDefaults(), web3ContractInstance,
this._web3Wrapper.getContractDefaults(),
); );
this._tokenRegistryContractIfExists = contractInstance; this._tokenRegistryContractIfExists = contractInstance;
return this._tokenRegistryContractIfExists; return this._tokenRegistryContractIfExists;

View File

@ -42,7 +42,8 @@ export class TokenTransferProxyWrapper extends ContractWrapper {
*/ */
public getContractAddress(): string { public getContractAddress(): string {
const contractAddress = this._getContractAddress( const contractAddress = this._getContractAddress(
artifacts.TokenTransferProxyArtifact, this._contractAddressIfExists, artifacts.TokenTransferProxyArtifact,
this._contractAddressIfExists,
); );
return contractAddress; return contractAddress;
} }
@ -54,10 +55,12 @@ export class TokenTransferProxyWrapper extends ContractWrapper {
return this._tokenTransferProxyContractIfExists; return this._tokenTransferProxyContractIfExists;
} }
const web3ContractInstance = await this._instantiateContractIfExistsAsync( const web3ContractInstance = await this._instantiateContractIfExistsAsync(
artifacts.TokenTransferProxyArtifact, this._contractAddressIfExists, artifacts.TokenTransferProxyArtifact,
this._contractAddressIfExists,
); );
const contractInstance = new TokenTransferProxyContract( const contractInstance = new TokenTransferProxyContract(
web3ContractInstance, this._web3Wrapper.getContractDefaults(), web3ContractInstance,
this._web3Wrapper.getContractDefaults(),
); );
this._tokenTransferProxyContractIfExists = contractInstance; this._tokenTransferProxyContractIfExists = contractInstance;
return this._tokenTransferProxyContractIfExists; return this._tokenTransferProxyContractIfExists;

View File

@ -32,8 +32,12 @@ export class TokenWrapper extends ContractWrapper {
public UNLIMITED_ALLOWANCE_IN_BASE_UNITS = constants.UNLIMITED_ALLOWANCE_IN_BASE_UNITS; public UNLIMITED_ALLOWANCE_IN_BASE_UNITS = constants.UNLIMITED_ALLOWANCE_IN_BASE_UNITS;
private _tokenContractsByAddress: { [address: string]: TokenContract }; private _tokenContractsByAddress: { [address: string]: TokenContract };
private _tokenTransferProxyWrapper: TokenTransferProxyWrapper; private _tokenTransferProxyWrapper: TokenTransferProxyWrapper;
constructor(web3Wrapper: Web3Wrapper, networkId: number, abiDecoder: AbiDecoder, constructor(
tokenTransferProxyWrapper: TokenTransferProxyWrapper) { web3Wrapper: Web3Wrapper,
networkId: number,
abiDecoder: AbiDecoder,
tokenTransferProxyWrapper: TokenTransferProxyWrapper,
) {
super(web3Wrapper, networkId, abiDecoder); super(web3Wrapper, networkId, abiDecoder);
this._tokenContractsByAddress = {}; this._tokenContractsByAddress = {};
this._tokenTransferProxyWrapper = tokenTransferProxyWrapper; this._tokenTransferProxyWrapper = tokenTransferProxyWrapper;
@ -45,8 +49,11 @@ export class TokenWrapper extends ContractWrapper {
* @param methodOpts Optional arguments this method accepts. * @param methodOpts Optional arguments this method accepts.
* @return The owner's ERC20 token balance in base units. * @return The owner's ERC20 token balance in base units.
*/ */
public async getBalanceAsync(tokenAddress: string, ownerAddress: string, public async getBalanceAsync(
methodOpts?: MethodOpts): Promise<BigNumber> { tokenAddress: string,
ownerAddress: string,
methodOpts?: MethodOpts,
): Promise<BigNumber> {
assert.isETHAddressHex('ownerAddress', ownerAddress); assert.isETHAddressHex('ownerAddress', ownerAddress);
assert.isETHAddressHex('tokenAddress', tokenAddress); assert.isETHAddressHex('tokenAddress', tokenAddress);
@ -68,8 +75,13 @@ export class TokenWrapper extends ContractWrapper {
* @param txOpts Transaction parameters. * @param txOpts Transaction parameters.
* @return Transaction hash. * @return Transaction hash.
*/ */
public async setAllowanceAsync(tokenAddress: string, ownerAddress: string, spenderAddress: string, public async setAllowanceAsync(
amountInBaseUnits: BigNumber, txOpts: TransactionOpts = {}): Promise<string> { tokenAddress: string,
ownerAddress: string,
spenderAddress: string,
amountInBaseUnits: BigNumber,
txOpts: TransactionOpts = {},
): Promise<string> {
await assert.isSenderAddressAsync('ownerAddress', ownerAddress, this._web3Wrapper); await assert.isSenderAddressAsync('ownerAddress', ownerAddress, this._web3Wrapper);
assert.isETHAddressHex('spenderAddress', spenderAddress); assert.isETHAddressHex('spenderAddress', spenderAddress);
assert.isETHAddressHex('tokenAddress', tokenAddress); assert.isETHAddressHex('tokenAddress', tokenAddress);
@ -95,10 +107,18 @@ export class TokenWrapper extends ContractWrapper {
* @param txOpts Transaction parameters. * @param txOpts Transaction parameters.
* @return Transaction hash. * @return Transaction hash.
*/ */
public async setUnlimitedAllowanceAsync(tokenAddress: string, ownerAddress: string, public async setUnlimitedAllowanceAsync(
spenderAddress: string, txOpts: TransactionOpts = {}): Promise<string> { tokenAddress: string,
ownerAddress: string,
spenderAddress: string,
txOpts: TransactionOpts = {},
): Promise<string> {
const txHash = await this.setAllowanceAsync( const txHash = await this.setAllowanceAsync(
tokenAddress, ownerAddress, spenderAddress, this.UNLIMITED_ALLOWANCE_IN_BASE_UNITS, txOpts, tokenAddress,
ownerAddress,
spenderAddress,
this.UNLIMITED_ALLOWANCE_IN_BASE_UNITS,
txOpts,
); );
return txHash; return txHash;
} }
@ -110,8 +130,12 @@ export class TokenWrapper extends ContractWrapper {
* @param spenderAddress The hex encoded user Ethereum address who can spend the allowance you are fetching. * @param spenderAddress The hex encoded user Ethereum address who can spend the allowance you are fetching.
* @param methodOpts Optional arguments this method accepts. * @param methodOpts Optional arguments this method accepts.
*/ */
public async getAllowanceAsync(tokenAddress: string, ownerAddress: string, public async getAllowanceAsync(
spenderAddress: string, methodOpts?: MethodOpts): Promise<BigNumber> { tokenAddress: string,
ownerAddress: string,
spenderAddress: string,
methodOpts?: MethodOpts,
): Promise<BigNumber> {
assert.isETHAddressHex('ownerAddress', ownerAddress); assert.isETHAddressHex('ownerAddress', ownerAddress);
assert.isETHAddressHex('tokenAddress', tokenAddress); assert.isETHAddressHex('tokenAddress', tokenAddress);
@ -128,8 +152,11 @@ export class TokenWrapper extends ContractWrapper {
* @param ownerAddress The hex encoded user Ethereum address whose proxy contract allowance we are retrieving. * @param ownerAddress The hex encoded user Ethereum address whose proxy contract allowance we are retrieving.
* @param methodOpts Optional arguments this method accepts. * @param methodOpts Optional arguments this method accepts.
*/ */
public async getProxyAllowanceAsync(tokenAddress: string, ownerAddress: string, public async getProxyAllowanceAsync(
methodOpts?: MethodOpts): Promise<BigNumber> { tokenAddress: string,
ownerAddress: string,
methodOpts?: MethodOpts,
): Promise<BigNumber> {
assert.isETHAddressHex('ownerAddress', ownerAddress); assert.isETHAddressHex('ownerAddress', ownerAddress);
assert.isETHAddressHex('tokenAddress', tokenAddress); assert.isETHAddressHex('tokenAddress', tokenAddress);
@ -147,15 +174,23 @@ export class TokenWrapper extends ContractWrapper {
* @param txOpts Transaction parameters. * @param txOpts Transaction parameters.
* @return Transaction hash. * @return Transaction hash.
*/ */
public async setProxyAllowanceAsync(tokenAddress: string, ownerAddress: string, public async setProxyAllowanceAsync(
amountInBaseUnits: BigNumber, txOpts: TransactionOpts = {}): Promise<string> { tokenAddress: string,
ownerAddress: string,
amountInBaseUnits: BigNumber,
txOpts: TransactionOpts = {},
): Promise<string> {
assert.isETHAddressHex('ownerAddress', ownerAddress); assert.isETHAddressHex('ownerAddress', ownerAddress);
assert.isETHAddressHex('tokenAddress', tokenAddress); assert.isETHAddressHex('tokenAddress', tokenAddress);
assert.isValidBaseUnitAmount('amountInBaseUnits', amountInBaseUnits); assert.isValidBaseUnitAmount('amountInBaseUnits', amountInBaseUnits);
const proxyAddress = this._tokenTransferProxyWrapper.getContractAddress(); const proxyAddress = this._tokenTransferProxyWrapper.getContractAddress();
const txHash = await this.setAllowanceAsync( const txHash = await this.setAllowanceAsync(
tokenAddress, ownerAddress, proxyAddress, amountInBaseUnits, txOpts, tokenAddress,
ownerAddress,
proxyAddress,
amountInBaseUnits,
txOpts,
); );
return txHash; return txHash;
} }
@ -171,10 +206,15 @@ export class TokenWrapper extends ContractWrapper {
* @return Transaction hash. * @return Transaction hash.
*/ */
public async setUnlimitedProxyAllowanceAsync( public async setUnlimitedProxyAllowanceAsync(
tokenAddress: string, ownerAddress: string, txOpts: TransactionOpts = {}, tokenAddress: string,
ownerAddress: string,
txOpts: TransactionOpts = {},
): Promise<string> { ): Promise<string> {
const txHash = await this.setProxyAllowanceAsync( const txHash = await this.setProxyAllowanceAsync(
tokenAddress, ownerAddress, this.UNLIMITED_ALLOWANCE_IN_BASE_UNITS, txOpts, tokenAddress,
ownerAddress,
this.UNLIMITED_ALLOWANCE_IN_BASE_UNITS,
txOpts,
); );
return txHash; return txHash;
} }
@ -187,8 +227,13 @@ export class TokenWrapper extends ContractWrapper {
* @param txOpts Transaction parameters. * @param txOpts Transaction parameters.
* @return Transaction hash. * @return Transaction hash.
*/ */
public async transferAsync(tokenAddress: string, fromAddress: string, toAddress: string, public async transferAsync(
amountInBaseUnits: BigNumber, txOpts: TransactionOpts = {}): Promise<string> { tokenAddress: string,
fromAddress: string,
toAddress: string,
amountInBaseUnits: BigNumber,
txOpts: TransactionOpts = {},
): Promise<string> {
assert.isETHAddressHex('tokenAddress', tokenAddress); assert.isETHAddressHex('tokenAddress', tokenAddress);
await assert.isSenderAddressAsync('fromAddress', fromAddress, this._web3Wrapper); await assert.isSenderAddressAsync('fromAddress', fromAddress, this._web3Wrapper);
assert.isETHAddressHex('toAddress', toAddress); assert.isETHAddressHex('toAddress', toAddress);
@ -222,9 +267,14 @@ export class TokenWrapper extends ContractWrapper {
* @param txOpts Transaction parameters. * @param txOpts Transaction parameters.
* @return Transaction hash. * @return Transaction hash.
*/ */
public async transferFromAsync(tokenAddress: string, fromAddress: string, toAddress: string, public async transferFromAsync(
senderAddress: string, amountInBaseUnits: BigNumber, txOpts: TransactionOpts = {}): tokenAddress: string,
Promise<string> { fromAddress: string,
toAddress: string,
senderAddress: string,
amountInBaseUnits: BigNumber,
txOpts: TransactionOpts = {},
): Promise<string> {
assert.isETHAddressHex('tokenAddress', tokenAddress); assert.isETHAddressHex('tokenAddress', tokenAddress);
assert.isETHAddressHex('fromAddress', fromAddress); assert.isETHAddressHex('fromAddress', fromAddress);
assert.isETHAddressHex('toAddress', toAddress); assert.isETHAddressHex('toAddress', toAddress);
@ -244,7 +294,9 @@ export class TokenWrapper extends ContractWrapper {
} }
const txHash = await tokenContract.transferFrom.sendTransactionAsync( const txHash = await tokenContract.transferFrom.sendTransactionAsync(
fromAddress, toAddress, amountInBaseUnits, fromAddress,
toAddress,
amountInBaseUnits,
{ {
from: senderAddress, from: senderAddress,
gas: txOpts.gasLimit, gas: txOpts.gasLimit,
@ -263,14 +315,21 @@ export class TokenWrapper extends ContractWrapper {
* @return Subscription token used later to unsubscribe * @return Subscription token used later to unsubscribe
*/ */
public subscribe<ArgsType extends TokenContractEventArgs>( public subscribe<ArgsType extends TokenContractEventArgs>(
tokenAddress: string, eventName: TokenEvents, indexFilterValues: IndexedFilterValues, tokenAddress: string,
callback: EventCallback<ArgsType>): string { eventName: TokenEvents,
indexFilterValues: IndexedFilterValues,
callback: EventCallback<ArgsType>,
): string {
assert.isETHAddressHex('tokenAddress', tokenAddress); assert.isETHAddressHex('tokenAddress', tokenAddress);
assert.doesBelongToStringEnum('eventName', eventName, TokenEvents); assert.doesBelongToStringEnum('eventName', eventName, TokenEvents);
assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema); assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema);
assert.isFunction('callback', callback); assert.isFunction('callback', callback);
const subscriptionToken = this._subscribe<ArgsType>( const subscriptionToken = this._subscribe<ArgsType>(
tokenAddress, eventName, indexFilterValues, artifacts.TokenArtifact.abi, callback, tokenAddress,
eventName,
indexFilterValues,
artifacts.TokenArtifact.abi,
callback,
); );
return subscriptionToken; return subscriptionToken;
} }
@ -297,14 +356,21 @@ export class TokenWrapper extends ContractWrapper {
* @return Array of logs that match the parameters * @return Array of logs that match the parameters
*/ */
public async getLogsAsync<ArgsType extends TokenContractEventArgs>( public async getLogsAsync<ArgsType extends TokenContractEventArgs>(
tokenAddress: string, eventName: TokenEvents, blockRange: BlockRange, tokenAddress: string,
indexFilterValues: IndexedFilterValues): Promise<Array<LogWithDecodedArgs<ArgsType>>> { eventName: TokenEvents,
blockRange: BlockRange,
indexFilterValues: IndexedFilterValues,
): Promise<Array<LogWithDecodedArgs<ArgsType>>> {
assert.isETHAddressHex('tokenAddress', tokenAddress); assert.isETHAddressHex('tokenAddress', tokenAddress);
assert.doesBelongToStringEnum('eventName', eventName, TokenEvents); assert.doesBelongToStringEnum('eventName', eventName, TokenEvents);
assert.doesConformToSchema('blockRange', blockRange, schemas.blockRangeSchema); assert.doesConformToSchema('blockRange', blockRange, schemas.blockRangeSchema);
assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema); assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema);
const logs = await this._getLogsAsync<ArgsType>( const logs = await this._getLogsAsync<ArgsType>(
tokenAddress, eventName, blockRange, indexFilterValues, artifacts.TokenArtifact.abi, tokenAddress,
eventName,
blockRange,
indexFilterValues,
artifacts.TokenArtifact.abi,
); );
return logs; return logs;
} }
@ -318,11 +384,10 @@ export class TokenWrapper extends ContractWrapper {
return tokenContract; return tokenContract;
} }
const web3ContractInstance = await this._instantiateContractIfExistsAsync( const web3ContractInstance = await this._instantiateContractIfExistsAsync(
artifacts.TokenArtifact, tokenAddress, artifacts.TokenArtifact,
); tokenAddress,
const contractInstance = new TokenContract(
web3ContractInstance, this._web3Wrapper.getContractDefaults(),
); );
const contractInstance = new TokenContract(web3ContractInstance, this._web3Wrapper.getContractDefaults());
tokenContract = contractInstance; tokenContract = contractInstance;
this._tokenContractsByAddress[tokenAddress] = tokenContract; this._tokenContractsByAddress[tokenAddress] = tokenContract;
return tokenContract; return tokenContract;

View File

@ -57,8 +57,7 @@ declare module 'truffle-hdwallet-provider' {
} }
// abi-decoder declarations // abi-decoder declarations
interface DecodedLogArg { interface DecodedLogArg {}
}
interface DecodedLog { interface DecodedLog {
name: string; name: string;
events: DecodedLogArg[]; events: DecodedLogArg[];

View File

@ -47,6 +47,4 @@ export {
OrderState, OrderState,
} from './types'; } from './types';
export { export { TransactionReceipt } from '@0xproject/types';
TransactionReceipt,
} from '@0xproject/types';

View File

@ -3,11 +3,7 @@ import {Web3Wrapper} from '@0xproject/web3-wrapper';
import * as _ from 'lodash'; import * as _ from 'lodash';
import * as Web3 from 'web3'; import * as Web3 from 'web3';
import { import { BlockParamLiteral, EventWatcherCallback, ZeroExError } from '../types';
BlockParamLiteral,
EventWatcherCallback,
ZeroExError,
} from '../types';
import { assert } from '../utils/assert'; import { assert } from '../utils/assert';
const DEFAULT_EVENT_POLLING_INTERVAL_MS = 200; const DEFAULT_EVENT_POLLING_INTERVAL_MS = 200;
@ -28,9 +24,9 @@ export class EventWatcher {
private _lastEvents: Web3.LogEntry[] = []; private _lastEvents: Web3.LogEntry[] = [];
constructor(web3Wrapper: Web3Wrapper, pollingIntervalIfExistsMs: undefined | number) { constructor(web3Wrapper: Web3Wrapper, pollingIntervalIfExistsMs: undefined | number) {
this._web3Wrapper = web3Wrapper; this._web3Wrapper = web3Wrapper;
this._pollingIntervalMs = _.isUndefined(pollingIntervalIfExistsMs) ? this._pollingIntervalMs = _.isUndefined(pollingIntervalIfExistsMs)
DEFAULT_EVENT_POLLING_INTERVAL_MS : ? DEFAULT_EVENT_POLLING_INTERVAL_MS
pollingIntervalIfExistsMs; : pollingIntervalIfExistsMs;
} }
public subscribe(callback: EventWatcherCallback): void { public subscribe(callback: EventWatcherCallback): void {
assert.isFunction('callback', callback); assert.isFunction('callback', callback);
@ -38,7 +34,8 @@ export class EventWatcher {
throw new Error(ZeroExError.SubscriptionAlreadyPresent); throw new Error(ZeroExError.SubscriptionAlreadyPresent);
} }
this._intervalIdIfExists = intervalUtils.setAsyncExcludingInterval( this._intervalIdIfExists = intervalUtils.setAsyncExcludingInterval(
this._pollForBlockchainEventsAsync.bind(this, callback), this._pollingIntervalMs, this._pollForBlockchainEventsAsync.bind(this, callback),
this._pollingIntervalMs,
); );
} }
public unsubscribe(): void { public unsubscribe(): void {
@ -71,7 +68,9 @@ export class EventWatcher {
return events; return events;
} }
private async _emitDifferencesAsync( private async _emitDifferencesAsync(
logs: Web3.LogEntry[], logEventState: LogEventState, callback: EventWatcherCallback, logs: Web3.LogEntry[],
logEventState: LogEventState,
callback: EventWatcherCallback,
): Promise<void> { ): Promise<void> {
for (const log of logs) { for (const log of logs) {
const logEvent = { const logEvent = {

View File

@ -19,12 +19,10 @@ export class ExpirationWatcher {
private _orderExpirationCheckingIntervalMs: number; private _orderExpirationCheckingIntervalMs: number;
private _expirationMarginMs: number; private _expirationMarginMs: number;
private _orderExpirationCheckingIntervalIdIfExists?: NodeJS.Timer; private _orderExpirationCheckingIntervalIdIfExists?: NodeJS.Timer;
constructor(expirationMarginIfExistsMs?: number, constructor(expirationMarginIfExistsMs?: number, orderExpirationCheckingIntervalIfExistsMs?: number) {
orderExpirationCheckingIntervalIfExistsMs?: number) { this._expirationMarginMs = expirationMarginIfExistsMs || DEFAULT_EXPIRATION_MARGIN_MS;
this._expirationMarginMs = expirationMarginIfExistsMs || this._orderExpirationCheckingIntervalMs =
DEFAULT_EXPIRATION_MARGIN_MS; expirationMarginIfExistsMs || DEFAULT_ORDER_EXPIRATION_CHECKING_INTERVAL_MS;
this._orderExpirationCheckingIntervalMs = expirationMarginIfExistsMs ||
DEFAULT_ORDER_EXPIRATION_CHECKING_INTERVAL_MS;
const scoreFunction = (orderHash: string) => this._expiration[orderHash].toNumber(); const scoreFunction = (orderHash: string) => this._expiration[orderHash].toNumber();
const comparator = (lhs: string, rhs: string) => scoreFunction(lhs) - scoreFunction(rhs); const comparator = (lhs: string, rhs: string) => scoreFunction(lhs) - scoreFunction(rhs);
this._orderHashByExpirationRBTree = new RBTree(comparator); this._orderHashByExpirationRBTree = new RBTree(comparator);
@ -34,7 +32,8 @@ export class ExpirationWatcher {
throw new Error(ZeroExError.SubscriptionAlreadyPresent); throw new Error(ZeroExError.SubscriptionAlreadyPresent);
} }
this._orderExpirationCheckingIntervalIdIfExists = intervalUtils.setAsyncExcludingInterval( this._orderExpirationCheckingIntervalIdIfExists = intervalUtils.setAsyncExcludingInterval(
this._pruneExpiredOrders.bind(this, callback), this._orderExpirationCheckingIntervalMs, this._pruneExpiredOrders.bind(this, callback),
this._orderExpirationCheckingIntervalMs,
); );
} }
public unsubscribe(): void { public unsubscribe(): void {

View File

@ -74,7 +74,10 @@ export class OrderStateWatcher {
private _cleanupJobInterval: number; private _cleanupJobInterval: number;
private _cleanupJobIntervalIdIfExists?: NodeJS.Timer; private _cleanupJobIntervalIdIfExists?: NodeJS.Timer;
constructor( constructor(
web3Wrapper: Web3Wrapper, abiDecoder: AbiDecoder, token: TokenWrapper, exchange: ExchangeWrapper, web3Wrapper: Web3Wrapper,
abiDecoder: AbiDecoder,
token: TokenWrapper,
exchange: ExchangeWrapper,
config?: OrderStateWatcherConfig, config?: OrderStateWatcherConfig,
) { ) {
this._abiDecoder = abiDecoder; this._abiDecoder = abiDecoder;
@ -82,24 +85,26 @@ export class OrderStateWatcher {
const pollingIntervalIfExistsMs = _.isUndefined(config) ? undefined : config.eventPollingIntervalMs; const pollingIntervalIfExistsMs = _.isUndefined(config) ? undefined : config.eventPollingIntervalMs;
this._eventWatcher = new EventWatcher(web3Wrapper, pollingIntervalIfExistsMs); this._eventWatcher = new EventWatcher(web3Wrapper, pollingIntervalIfExistsMs);
this._balanceAndProxyAllowanceLazyStore = new BalanceAndProxyAllowanceLazyStore( this._balanceAndProxyAllowanceLazyStore = new BalanceAndProxyAllowanceLazyStore(
token, BlockParamLiteral.Pending, token,
BlockParamLiteral.Pending,
); );
this._orderFilledCancelledLazyStore = new OrderFilledCancelledLazyStore(exchange); this._orderFilledCancelledLazyStore = new OrderFilledCancelledLazyStore(exchange);
this._orderStateUtils = new OrderStateUtils( this._orderStateUtils = new OrderStateUtils(
this._balanceAndProxyAllowanceLazyStore, this._orderFilledCancelledLazyStore, this._balanceAndProxyAllowanceLazyStore,
this._orderFilledCancelledLazyStore,
); );
const orderExpirationCheckingIntervalMsIfExists = _.isUndefined(config) ? const orderExpirationCheckingIntervalMsIfExists = _.isUndefined(config)
undefined : ? undefined
config.orderExpirationCheckingIntervalMs; : config.orderExpirationCheckingIntervalMs;
const expirationMarginIfExistsMs = _.isUndefined(config) ? const expirationMarginIfExistsMs = _.isUndefined(config) ? undefined : config.expirationMarginMs;
undefined :
config.expirationMarginMs;
this._expirationWatcher = new ExpirationWatcher( this._expirationWatcher = new ExpirationWatcher(
expirationMarginIfExistsMs, orderExpirationCheckingIntervalMsIfExists, expirationMarginIfExistsMs,
orderExpirationCheckingIntervalMsIfExists,
); );
this._cleanupJobInterval = _.isUndefined(config) || _.isUndefined(config.cleanupJobIntervalMs) ? this._cleanupJobInterval =
DEFAULT_CLEANUP_JOB_INTERVAL_MS : _.isUndefined(config) || _.isUndefined(config.cleanupJobIntervalMs)
config.cleanupJobIntervalMs; ? DEFAULT_CLEANUP_JOB_INTERVAL_MS
: config.cleanupJobIntervalMs;
} }
/** /**
* Add an order to the orderStateWatcher. Before the order is added, it's * Add an order to the orderStateWatcher. Before the order is added, it's
@ -148,7 +153,8 @@ export class OrderStateWatcher {
this._eventWatcher.subscribe(this._onEventWatcherCallbackAsync.bind(this)); this._eventWatcher.subscribe(this._onEventWatcherCallbackAsync.bind(this));
this._expirationWatcher.subscribe(this._onOrderExpired.bind(this)); this._expirationWatcher.subscribe(this._onOrderExpired.bind(this));
this._cleanupJobIntervalIdIfExists = intervalUtils.setAsyncExcludingInterval( this._cleanupJobIntervalIdIfExists = intervalUtils.setAsyncExcludingInterval(
this._cleanupAsync.bind(this), this._cleanupJobInterval, this._cleanupAsync.bind(this),
this._cleanupJobInterval,
); );
} }
/** /**
@ -215,23 +221,23 @@ export class OrderStateWatcher {
let makerToken: string; let makerToken: string;
let makerAddress: string; let makerAddress: string;
switch (decodedLog.event) { switch (decodedLog.event) {
case TokenEvents.Approval: case TokenEvents.Approval: {
{
// Invalidate cache // Invalidate cache
const args = decodedLog.args as ApprovalContractEventArgs; const args = decodedLog.args as ApprovalContractEventArgs;
this._balanceAndProxyAllowanceLazyStore.deleteProxyAllowance(decodedLog.address, args._owner); this._balanceAndProxyAllowanceLazyStore.deleteProxyAllowance(decodedLog.address, args._owner);
// Revalidate orders // Revalidate orders
makerToken = decodedLog.address; makerToken = decodedLog.address;
makerAddress = args._owner; makerAddress = args._owner;
if (!_.isUndefined(this._dependentOrderHashes[makerAddress]) && if (
!_.isUndefined(this._dependentOrderHashes[makerAddress][makerToken])) { !_.isUndefined(this._dependentOrderHashes[makerAddress]) &&
!_.isUndefined(this._dependentOrderHashes[makerAddress][makerToken])
) {
const orderHashes = Array.from(this._dependentOrderHashes[makerAddress][makerToken]); const orderHashes = Array.from(this._dependentOrderHashes[makerAddress][makerToken]);
await this._emitRevalidateOrdersAsync(orderHashes); await this._emitRevalidateOrdersAsync(orderHashes);
} }
break; break;
} }
case TokenEvents.Transfer: case TokenEvents.Transfer: {
{
// Invalidate cache // Invalidate cache
const args = decodedLog.args as TransferContractEventArgs; const args = decodedLog.args as TransferContractEventArgs;
this._balanceAndProxyAllowanceLazyStore.deleteBalance(decodedLog.address, args._from); this._balanceAndProxyAllowanceLazyStore.deleteBalance(decodedLog.address, args._from);
@ -239,45 +245,48 @@ export class OrderStateWatcher {
// Revalidate orders // Revalidate orders
makerToken = decodedLog.address; makerToken = decodedLog.address;
makerAddress = args._from; makerAddress = args._from;
if (!_.isUndefined(this._dependentOrderHashes[makerAddress]) && if (
!_.isUndefined(this._dependentOrderHashes[makerAddress][makerToken])) { !_.isUndefined(this._dependentOrderHashes[makerAddress]) &&
!_.isUndefined(this._dependentOrderHashes[makerAddress][makerToken])
) {
const orderHashes = Array.from(this._dependentOrderHashes[makerAddress][makerToken]); const orderHashes = Array.from(this._dependentOrderHashes[makerAddress][makerToken]);
await this._emitRevalidateOrdersAsync(orderHashes); await this._emitRevalidateOrdersAsync(orderHashes);
} }
break; break;
} }
case EtherTokenEvents.Deposit: case EtherTokenEvents.Deposit: {
{
// Invalidate cache // Invalidate cache
const args = decodedLog.args as DepositContractEventArgs; const args = decodedLog.args as DepositContractEventArgs;
this._balanceAndProxyAllowanceLazyStore.deleteBalance(decodedLog.address, args._owner); this._balanceAndProxyAllowanceLazyStore.deleteBalance(decodedLog.address, args._owner);
// Revalidate orders // Revalidate orders
makerToken = decodedLog.address; makerToken = decodedLog.address;
makerAddress = args._owner; makerAddress = args._owner;
if (!_.isUndefined(this._dependentOrderHashes[makerAddress]) && if (
!_.isUndefined(this._dependentOrderHashes[makerAddress][makerToken])) { !_.isUndefined(this._dependentOrderHashes[makerAddress]) &&
!_.isUndefined(this._dependentOrderHashes[makerAddress][makerToken])
) {
const orderHashes = Array.from(this._dependentOrderHashes[makerAddress][makerToken]); const orderHashes = Array.from(this._dependentOrderHashes[makerAddress][makerToken]);
await this._emitRevalidateOrdersAsync(orderHashes); await this._emitRevalidateOrdersAsync(orderHashes);
} }
break; break;
} }
case EtherTokenEvents.Withdrawal: case EtherTokenEvents.Withdrawal: {
{
// Invalidate cache // Invalidate cache
const args = decodedLog.args as WithdrawalContractEventArgs; const args = decodedLog.args as WithdrawalContractEventArgs;
this._balanceAndProxyAllowanceLazyStore.deleteBalance(decodedLog.address, args._owner); this._balanceAndProxyAllowanceLazyStore.deleteBalance(decodedLog.address, args._owner);
// Revalidate orders // Revalidate orders
makerToken = decodedLog.address; makerToken = decodedLog.address;
makerAddress = args._owner; makerAddress = args._owner;
if (!_.isUndefined(this._dependentOrderHashes[makerAddress]) && if (
!_.isUndefined(this._dependentOrderHashes[makerAddress][makerToken])) { !_.isUndefined(this._dependentOrderHashes[makerAddress]) &&
!_.isUndefined(this._dependentOrderHashes[makerAddress][makerToken])
) {
const orderHashes = Array.from(this._dependentOrderHashes[makerAddress][makerToken]); const orderHashes = Array.from(this._dependentOrderHashes[makerAddress][makerToken]);
await this._emitRevalidateOrdersAsync(orderHashes); await this._emitRevalidateOrdersAsync(orderHashes);
} }
break; break;
} }
case ExchangeEvents.LogFill: case ExchangeEvents.LogFill: {
{
// Invalidate cache // Invalidate cache
const args = decodedLog.args as LogFillContractEventArgs; const args = decodedLog.args as LogFillContractEventArgs;
this._orderFilledCancelledLazyStore.deleteFilledTakerAmount(args.orderHash); this._orderFilledCancelledLazyStore.deleteFilledTakerAmount(args.orderHash);
@ -289,8 +298,7 @@ export class OrderStateWatcher {
} }
break; break;
} }
case ExchangeEvents.LogCancel: case ExchangeEvents.LogCancel: {
{
// Invalidate cache // Invalidate cache
const args = decodedLog.args as LogCancelContractEventArgs; const args = decodedLog.args as LogCancelContractEventArgs;
this._orderFilledCancelledLazyStore.deleteCancelledTakerAmount(args.orderHash); this._orderFilledCancelledLazyStore.deleteCancelledTakerAmount(args.orderHash);

View File

@ -10,17 +10,20 @@ export class RemainingFillableCalculator {
private _transferrableMakerFeeTokenAmount: BigNumber; private _transferrableMakerFeeTokenAmount: BigNumber;
private _remainingMakerTokenAmount: BigNumber; private _remainingMakerTokenAmount: BigNumber;
private _remainingMakerFeeAmount: BigNumber; private _remainingMakerFeeAmount: BigNumber;
constructor(signedOrder: SignedOrder, constructor(
signedOrder: SignedOrder,
isMakerTokenZRX: boolean, isMakerTokenZRX: boolean,
transferrableMakerTokenAmount: BigNumber, transferrableMakerTokenAmount: BigNumber,
transferrableMakerFeeTokenAmount: BigNumber, transferrableMakerFeeTokenAmount: BigNumber,
remainingMakerTokenAmount: BigNumber) { remainingMakerTokenAmount: BigNumber,
) {
this._signedOrder = signedOrder; this._signedOrder = signedOrder;
this._isMakerTokenZRX = isMakerTokenZRX; this._isMakerTokenZRX = isMakerTokenZRX;
this._transferrableMakerTokenAmount = transferrableMakerTokenAmount; this._transferrableMakerTokenAmount = transferrableMakerTokenAmount;
this._transferrableMakerFeeTokenAmount = transferrableMakerFeeTokenAmount; this._transferrableMakerFeeTokenAmount = transferrableMakerFeeTokenAmount;
this._remainingMakerTokenAmount = remainingMakerTokenAmount; this._remainingMakerTokenAmount = remainingMakerTokenAmount;
this._remainingMakerFeeAmount = remainingMakerTokenAmount.times(signedOrder.makerFee) this._remainingMakerFeeAmount = remainingMakerTokenAmount
.times(signedOrder.makerFee)
.dividedToIntegerBy(signedOrder.makerTokenAmount); .dividedToIntegerBy(signedOrder.makerTokenAmount);
} }
public computeRemainingMakerFillable(): BigNumber { public computeRemainingMakerFillable(): BigNumber {
@ -33,20 +36,24 @@ export class RemainingFillableCalculator {
return this._calculatePartiallyFillableMakerTokenAmount(); return this._calculatePartiallyFillableMakerTokenAmount();
} }
public computeRemainingTakerFillable(): BigNumber { public computeRemainingTakerFillable(): BigNumber {
return this.computeRemainingMakerFillable().times(this._signedOrder.takerTokenAmount) return this.computeRemainingMakerFillable()
.times(this._signedOrder.takerTokenAmount)
.dividedToIntegerBy(this._signedOrder.makerTokenAmount); .dividedToIntegerBy(this._signedOrder.makerTokenAmount);
} }
private _hasSufficientFundsForFeeAndTransferAmount(): boolean { private _hasSufficientFundsForFeeAndTransferAmount(): boolean {
if (this._isMakerTokenZRX) { if (this._isMakerTokenZRX) {
const totalZRXTransferAmountRequired = this._remainingMakerTokenAmount.plus(this._remainingMakerFeeAmount); const totalZRXTransferAmountRequired = this._remainingMakerTokenAmount.plus(this._remainingMakerFeeAmount);
const hasSufficientFunds = this._transferrableMakerTokenAmount.greaterThanOrEqualTo( const hasSufficientFunds = this._transferrableMakerTokenAmount.greaterThanOrEqualTo(
totalZRXTransferAmountRequired); totalZRXTransferAmountRequired,
);
return hasSufficientFunds; return hasSufficientFunds;
} else { } else {
const hasSufficientFundsForTransferAmount = this._transferrableMakerTokenAmount.greaterThanOrEqualTo( const hasSufficientFundsForTransferAmount = this._transferrableMakerTokenAmount.greaterThanOrEqualTo(
this._remainingMakerTokenAmount); this._remainingMakerTokenAmount,
);
const hasSufficientFundsForFeeAmount = this._transferrableMakerFeeTokenAmount.greaterThanOrEqualTo( const hasSufficientFundsForFeeAmount = this._transferrableMakerFeeTokenAmount.greaterThanOrEqualTo(
this._remainingMakerFeeAmount); this._remainingMakerFeeAmount,
);
const hasSufficientFunds = hasSufficientFundsForTransferAmount && hasSufficientFundsForFeeAmount; const hasSufficientFunds = hasSufficientFundsForTransferAmount && hasSufficientFundsForFeeAmount;
return hasSufficientFunds; return hasSufficientFunds;
} }
@ -57,8 +64,10 @@ export class RemainingFillableCalculator {
// The number of times the maker can fill the order, if each fill only required the transfer of a single // The number of times the maker can fill the order, if each fill only required the transfer of a single
// baseUnit of fee tokens. // baseUnit of fee tokens.
// Given 2 ZRXwei, the maximum amount of times Maker can fill this order, in terms of fees, is 2 // Given 2 ZRXwei, the maximum amount of times Maker can fill this order, in terms of fees, is 2
const fillableTimesInFeeTokenBaseUnits = BigNumber.min(this._transferrableMakerFeeTokenAmount, const fillableTimesInFeeTokenBaseUnits = BigNumber.min(
this._remainingMakerFeeAmount); this._transferrableMakerFeeTokenAmount,
this._remainingMakerFeeAmount,
);
// The number of times the Maker can fill the order, given the Maker Token Balance // The number of times the Maker can fill the order, given the Maker Token Balance
// Assuming a balance of 150 wei, and an orderToFeeRatio of 100:1, maker can fill this order 1 time. // Assuming a balance of 150 wei, and an orderToFeeRatio of 100:1, maker can fill this order 1 time.
let fillableTimesInMakerTokenUnits = this._transferrableMakerTokenAmount.dividedBy(orderToFeeRatio); let fillableTimesInMakerTokenUnits = this._transferrableMakerTokenAmount.dividedBy(orderToFeeRatio);
@ -68,9 +77,7 @@ export class RemainingFillableCalculator {
const totalZRXTokenPooled = this._transferrableMakerTokenAmount; const totalZRXTokenPooled = this._transferrableMakerTokenAmount;
// The purchasing power here is less as the tokens are taken from the same Pool // The purchasing power here is less as the tokens are taken from the same Pool
// For every one number of fills, we have to take an extra ZRX out of the pool // For every one number of fills, we have to take an extra ZRX out of the pool
fillableTimesInMakerTokenUnits = totalZRXTokenPooled.dividedBy( fillableTimesInMakerTokenUnits = totalZRXTokenPooled.dividedBy(orderToFeeRatio.plus(new BigNumber(1)));
orderToFeeRatio.plus(new BigNumber(1)));
} }
// When Ratio is not fully divisible there can be remainders which cannot be represented, so they are floored. // When Ratio is not fully divisible there can be remainders which cannot be represented, so they are floored.
// This can result in a RoundingError being thrown by the Exchange Contract. // This can result in a RoundingError being thrown by the Exchange Contract.
@ -80,8 +87,10 @@ export class RemainingFillableCalculator {
const partiallyFillableFeeTokenAmount = fillableTimesInFeeTokenBaseUnits const partiallyFillableFeeTokenAmount = fillableTimesInFeeTokenBaseUnits
.times(this._signedOrder.makerTokenAmount) .times(this._signedOrder.makerTokenAmount)
.dividedToIntegerBy(this._signedOrder.makerFee); .dividedToIntegerBy(this._signedOrder.makerFee);
const partiallyFillableAmount = BigNumber.min(partiallyFillableMakerTokenAmount, const partiallyFillableAmount = BigNumber.min(
partiallyFillableFeeTokenAmount); partiallyFillableMakerTokenAmount,
partiallyFillableFeeTokenAmount,
);
return partiallyFillableAmount; return partiallyFillableAmount;
} }
} }

View File

@ -52,8 +52,10 @@ export class BalanceAndProxyAllowanceLazyStore {
} }
} }
public async getProxyAllowanceAsync(tokenAddress: string, userAddress: string): Promise<BigNumber> { public async getProxyAllowanceAsync(tokenAddress: string, userAddress: string): Promise<BigNumber> {
if (_.isUndefined(this._proxyAllowance[tokenAddress]) || if (
_.isUndefined(this._proxyAllowance[tokenAddress][userAddress])) { _.isUndefined(this._proxyAllowance[tokenAddress]) ||
_.isUndefined(this._proxyAllowance[tokenAddress][userAddress])
) {
const methodOpts = { const methodOpts = {
defaultBlock: this._defaultBlock, defaultBlock: this._defaultBlock,
}; };

View File

@ -42,8 +42,7 @@ export interface ECSignature {
export type OrderAddresses = [string, string, string, string, string]; export type OrderAddresses = [string, string, string, string, string];
export type OrderValues = [BigNumber, BigNumber, BigNumber, export type OrderValues = [BigNumber, BigNumber, BigNumber, BigNumber, BigNumber, BigNumber];
BigNumber, BigNumber, BigNumber];
export type LogEvent = Web3.LogEntryEvent; export type LogEvent = Web3.LogEntryEvent;
export interface DecodedLogEvent<ArgsType> { export interface DecodedLogEvent<ArgsType> {
@ -136,7 +135,10 @@ export interface LogErrorContractEventArgs {
errorId: BigNumber; errorId: BigNumber;
orderHash: string; orderHash: string;
} }
export type ExchangeContractEventArgs = LogFillContractEventArgs|LogCancelContractEventArgs|LogErrorContractEventArgs; export type ExchangeContractEventArgs =
| LogFillContractEventArgs
| LogCancelContractEventArgs
| LogErrorContractEventArgs;
export interface TransferContractEventArgs { export interface TransferContractEventArgs {
_from: string; _from: string;
_to: string; _to: string;
@ -156,7 +158,10 @@ export interface WithdrawalContractEventArgs {
_value: BigNumber; _value: BigNumber;
} }
export type TokenContractEventArgs = TransferContractEventArgs | ApprovalContractEventArgs; export type TokenContractEventArgs = TransferContractEventArgs | ApprovalContractEventArgs;
export type EtherTokenContractEventArgs = TokenContractEventArgs|DepositContractEventArgs|WithdrawalContractEventArgs; export type EtherTokenContractEventArgs =
| TokenContractEventArgs
| DepositContractEventArgs
| WithdrawalContractEventArgs;
export type ContractEventArgs = ExchangeContractEventArgs | TokenContractEventArgs | EtherTokenContractEventArgs; export type ContractEventArgs = ExchangeContractEventArgs | TokenContractEventArgs | EtherTokenContractEventArgs;
export type ContractEventArg = string | BigNumber; export type ContractEventArg = string | BigNumber;

View File

@ -22,7 +22,8 @@ export class AbiDecoder {
} }
// This method can only decode logs from the 0x & ERC20 smart contracts // This method can only decode logs from the 0x & ERC20 smart contracts
public tryToDecodeLogOrNoop<ArgsType extends ContractEventArgs>( public tryToDecodeLogOrNoop<ArgsType extends ContractEventArgs>(
log: Web3.LogEntry): LogWithDecodedArgs<ArgsType>|RawLog { log: Web3.LogEntry,
): LogWithDecodedArgs<ArgsType> | RawLog {
const methodId = log.topics[0]; const methodId = log.topics[0];
const event = this._methodIds[methodId]; const event = this._methodIds[methodId];
if (_.isUndefined(event)) { if (_.isUndefined(event)) {
@ -42,9 +43,11 @@ export class AbiDecoder {
let value = param.indexed ? log.topics[topicsIndex++] : decodedData[dataIndex++]; let value = param.indexed ? log.topics[topicsIndex++] : decodedData[dataIndex++];
if (param.type === SolidityTypes.Address) { if (param.type === SolidityTypes.Address) {
value = AbiDecoder._padZeros(new BigNumber(value).toString(16)); value = AbiDecoder._padZeros(new BigNumber(value).toString(16));
} else if (param.type === SolidityTypes.Uint256 || } else if (
param.type === SolidityTypes.Uint256 ||
param.type === SolidityTypes.Uint8 || param.type === SolidityTypes.Uint8 ||
param.type === SolidityTypes.Uint) { param.type === SolidityTypes.Uint
) {
value = new BigNumber(value); value = new BigNumber(value);
} }
decodedParams[param.name] = value; decodedParams[param.name] = value;

View File

@ -16,11 +16,15 @@ export const assert = {
const isValidSignature = signatureUtils.isValidSignature(orderHash, ecSignature, signerAddress); const isValidSignature = signatureUtils.isValidSignature(orderHash, ecSignature, signerAddress);
this.assert(isValidSignature, `Expected order with hash '${orderHash}' to have a valid signature`); this.assert(isValidSignature, `Expected order with hash '${orderHash}' to have a valid signature`);
}, },
async isSenderAddressAsync(variableName: string, senderAddressHex: string, async isSenderAddressAsync(
web3Wrapper: Web3Wrapper): Promise<void> { variableName: string,
senderAddressHex: string,
web3Wrapper: Web3Wrapper,
): Promise<void> {
sharedAssert.isETHAddressHex(variableName, senderAddressHex); sharedAssert.isETHAddressHex(variableName, senderAddressHex);
const isSenderAddressAvailable = await web3Wrapper.isSenderAddressAvailableAsync(senderAddressHex); const isSenderAddressAvailable = await web3Wrapper.isSenderAddressAvailableAsync(senderAddressHex);
sharedAssert.assert(isSenderAddressAvailable, sharedAssert.assert(
isSenderAddressAvailable,
`Specified ${variableName} ${senderAddressHex} isn't available through the supplied web3 provider`, `Specified ${variableName} ${senderAddressHex} isn't available through the supplied web3 provider`,
); );
}, },

View File

@ -19,7 +19,8 @@ const contractCallErrorTransformer = (error: Error) => {
const schemaErrorTransformer = (error: Error) => { const schemaErrorTransformer = (error: Error) => {
if (_.includes(error.message, constants.INVALID_TAKER_FORMAT)) { if (_.includes(error.message, constants.INVALID_TAKER_FORMAT)) {
// tslint:disable-next-line:max-line-length // 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'; const errMsg =
'Order taker must be of type string. If you want anyone to be able to fill an order - pass ZeroEx.NULL_ADDRESS';
return new Error(errMsg); return new Error(errMsg);
} }
return error; return error;
@ -30,9 +31,11 @@ const schemaErrorTransformer = (error: Error) => {
*/ */
const asyncErrorHandlerFactory = (errorTransformer: ErrorTransformer) => { const asyncErrorHandlerFactory = (errorTransformer: ErrorTransformer) => {
const asyncErrorHandlingDecorator = ( const asyncErrorHandlingDecorator = (
target: object, key: string|symbol, descriptor: TypedPropertyDescriptor<AsyncMethod>, 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
// order to use the correct value of `this` in this method // order to use the correct value of `this` in this method
@ -55,9 +58,11 @@ const asyncErrorHandlerFactory = (errorTransformer: ErrorTransformer) => {
const syncErrorHandlerFactory = (errorTransformer: ErrorTransformer) => { const syncErrorHandlerFactory = (errorTransformer: ErrorTransformer) => {
const syncErrorHandlingDecorator = ( const syncErrorHandlingDecorator = (
target: object, key: string|symbol, descriptor: TypedPropertyDescriptor<SyncMethod>, target: object,
key: string | symbol,
descriptor: TypedPropertyDescriptor<SyncMethod>,
) => { ) => {
const originalMethod = (descriptor.value as SyncMethod); const originalMethod = descriptor.value as SyncMethod;
// Do not use arrow syntax here. Use a function expression in // Do not use arrow syntax here. Use a function expression in
// order to use the correct value of `this` in this method // order to use the correct value of `this` in this method

View File

@ -36,8 +36,11 @@ const ERR_MSG_MAPPING = {
export class ExchangeTransferSimulator { export class ExchangeTransferSimulator {
private _store: BalanceAndProxyAllowanceLazyStore; private _store: BalanceAndProxyAllowanceLazyStore;
private _UNLIMITED_ALLOWANCE_IN_BASE_UNITS: BigNumber; private _UNLIMITED_ALLOWANCE_IN_BASE_UNITS: BigNumber;
private static _throwValidationError(failureReason: FailureReason, tradeSide: TradeSide, private static _throwValidationError(
transferType: TransferType): never { failureReason: FailureReason,
tradeSide: TradeSide,
transferType: TransferType,
): never {
const errMsg = ERR_MSG_MAPPING[failureReason][tradeSide][transferType]; const errMsg = ERR_MSG_MAPPING[failureReason][tradeSide][transferType];
throw new Error(errMsg); throw new Error(errMsg);
} }
@ -54,9 +57,14 @@ export class ExchangeTransferSimulator {
* @param tradeSide Is Maker/Taker transferring * @param tradeSide Is Maker/Taker transferring
* @param transferType Is it a fee payment or a value transfer * @param transferType Is it a fee payment or a value transfer
*/ */
public async transferFromAsync(tokenAddress: string, from: string, to: string, public async transferFromAsync(
amountInBaseUnits: BigNumber, tradeSide: TradeSide, tokenAddress: string,
transferType: TransferType): Promise<void> { from: string,
to: string,
amountInBaseUnits: BigNumber,
tradeSide: TradeSide,
transferType: TransferType,
): Promise<void> {
const balance = await this._store.getBalanceAsync(tokenAddress, from); const balance = await this._store.getBalanceAsync(tokenAddress, from);
const proxyAllowance = await this._store.getProxyAllowanceAsync(tokenAddress, from); const proxyAllowance = await this._store.getProxyAllowanceAsync(tokenAddress, from);
if (proxyAllowance.lessThan(amountInBaseUnits)) { if (proxyAllowance.lessThan(amountInBaseUnits)) {
@ -69,20 +77,29 @@ export class ExchangeTransferSimulator {
await this._decreaseBalanceAsync(tokenAddress, from, amountInBaseUnits); await this._decreaseBalanceAsync(tokenAddress, from, amountInBaseUnits);
await this._increaseBalanceAsync(tokenAddress, to, amountInBaseUnits); await this._increaseBalanceAsync(tokenAddress, to, amountInBaseUnits);
} }
private async _decreaseProxyAllowanceAsync(tokenAddress: string, userAddress: string, private async _decreaseProxyAllowanceAsync(
amountInBaseUnits: BigNumber): Promise<void> { tokenAddress: string,
userAddress: string,
amountInBaseUnits: BigNumber,
): Promise<void> {
const proxyAllowance = await this._store.getProxyAllowanceAsync(tokenAddress, userAddress); const proxyAllowance = await this._store.getProxyAllowanceAsync(tokenAddress, userAddress);
if (!proxyAllowance.eq(this._UNLIMITED_ALLOWANCE_IN_BASE_UNITS)) { if (!proxyAllowance.eq(this._UNLIMITED_ALLOWANCE_IN_BASE_UNITS)) {
this._store.setProxyAllowance(tokenAddress, userAddress, proxyAllowance.minus(amountInBaseUnits)); this._store.setProxyAllowance(tokenAddress, userAddress, proxyAllowance.minus(amountInBaseUnits));
} }
} }
private async _increaseBalanceAsync(tokenAddress: string, userAddress: string, private async _increaseBalanceAsync(
amountInBaseUnits: BigNumber): Promise<void> { tokenAddress: string,
userAddress: string,
amountInBaseUnits: BigNumber,
): Promise<void> {
const balance = await this._store.getBalanceAsync(tokenAddress, userAddress); const balance = await this._store.getBalanceAsync(tokenAddress, userAddress);
this._store.setBalance(tokenAddress, userAddress, balance.plus(amountInBaseUnits)); this._store.setBalance(tokenAddress, userAddress, balance.plus(amountInBaseUnits));
} }
private async _decreaseBalanceAsync(tokenAddress: string, userAddress: string, private async _decreaseBalanceAsync(
amountInBaseUnits: BigNumber): Promise<void> { tokenAddress: string,
userAddress: string,
amountInBaseUnits: BigNumber,
): Promise<void> {
const balance = await this._store.getBalanceAsync(tokenAddress, userAddress); const balance = await this._store.getBalanceAsync(tokenAddress, userAddress);
this._store.setBalance(tokenAddress, userAddress, balance.minus(amountInBaseUnits)); this._store.setBalance(tokenAddress, userAddress, balance.minus(amountInBaseUnits));
} }

View File

@ -12,9 +12,13 @@ export const filterUtils = {
generateUUID(): string { generateUUID(): string {
return uuid(); return uuid();
}, },
getFilter(address: string, eventName: ContractEvents, getFilter(
indexFilterValues: IndexedFilterValues, abi: Web3.ContractAbi, address: string,
blockRange?: BlockRange): Web3.FilterObject { eventName: ContractEvents,
indexFilterValues: IndexedFilterValues,
abi: Web3.ContractAbi,
blockRange?: BlockRange,
): Web3.FilterObject {
const eventAbi = _.find(abi, { name: eventName }) as Web3.EventAbi; const eventAbi = _.find(abi, { name: eventName }) as Web3.EventAbi;
const eventSignature = filterUtils.getEventSignatureFromAbiByName(eventAbi, eventName); const eventSignature = filterUtils.getEventSignatureFromAbiByName(eventAbi, eventName);
const topicForEventSignature = ethUtil.addHexPrefix(jsSHA3.keccak256(eventSignature)); const topicForEventSignature = ethUtil.addHexPrefix(jsSHA3.keccak256(eventSignature));

View File

@ -46,13 +46,18 @@ export class OrderStateUtils {
const minFillableTakerTokenAmountWithinNoRoundingErrorRange = signedOrder.takerTokenAmount const minFillableTakerTokenAmountWithinNoRoundingErrorRange = signedOrder.takerTokenAmount
.dividedBy(ACCEPTABLE_RELATIVE_ROUNDING_ERROR) .dividedBy(ACCEPTABLE_RELATIVE_ROUNDING_ERROR)
.dividedBy(signedOrder.makerTokenAmount); .dividedBy(signedOrder.makerTokenAmount);
if (orderRelevantState.remainingFillableTakerTokenAmount if (
.lessThan(minFillableTakerTokenAmountWithinNoRoundingErrorRange)) { orderRelevantState.remainingFillableTakerTokenAmount.lessThan(
minFillableTakerTokenAmountWithinNoRoundingErrorRange,
)
) {
throw new Error(ExchangeContractErrs.OrderFillRoundingError); throw new Error(ExchangeContractErrs.OrderFillRoundingError);
} }
} }
constructor(balanceAndProxyAllowanceLazyStore: BalanceAndProxyAllowanceLazyStore, constructor(
orderFilledCancelledLazyStore: OrderFilledCancelledLazyStore) { balanceAndProxyAllowanceLazyStore: BalanceAndProxyAllowanceLazyStore,
orderFilledCancelledLazyStore: OrderFilledCancelledLazyStore,
) {
this._balanceAndProxyAllowanceLazyStore = balanceAndProxyAllowanceLazyStore; this._balanceAndProxyAllowanceLazyStore = balanceAndProxyAllowanceLazyStore;
this._orderFilledCancelledLazyStore = orderFilledCancelledLazyStore; this._orderFilledCancelledLazyStore = orderFilledCancelledLazyStore;
} }
@ -85,16 +90,20 @@ export class OrderStateUtils {
const zrxTokenAddress = exchange.getZRXTokenAddress(); const zrxTokenAddress = exchange.getZRXTokenAddress();
const orderHash = ZeroEx.getOrderHashHex(signedOrder); const orderHash = ZeroEx.getOrderHashHex(signedOrder);
const makerBalance = await this._balanceAndProxyAllowanceLazyStore.getBalanceAsync( const makerBalance = await this._balanceAndProxyAllowanceLazyStore.getBalanceAsync(
signedOrder.makerTokenAddress, signedOrder.maker, signedOrder.makerTokenAddress,
signedOrder.maker,
); );
const makerProxyAllowance = await this._balanceAndProxyAllowanceLazyStore.getProxyAllowanceAsync( const makerProxyAllowance = await this._balanceAndProxyAllowanceLazyStore.getProxyAllowanceAsync(
signedOrder.makerTokenAddress, signedOrder.maker, signedOrder.makerTokenAddress,
signedOrder.maker,
); );
const makerFeeBalance = await this._balanceAndProxyAllowanceLazyStore.getBalanceAsync( const makerFeeBalance = await this._balanceAndProxyAllowanceLazyStore.getBalanceAsync(
zrxTokenAddress, signedOrder.maker, zrxTokenAddress,
signedOrder.maker,
); );
const makerFeeProxyAllowance = await this._balanceAndProxyAllowanceLazyStore.getProxyAllowanceAsync( const makerFeeProxyAllowance = await this._balanceAndProxyAllowanceLazyStore.getProxyAllowanceAsync(
zrxTokenAddress, signedOrder.maker, zrxTokenAddress,
signedOrder.maker,
); );
const filledTakerTokenAmount = await this._orderFilledCancelledLazyStore.getFilledTakerAmountAsync(orderHash); const filledTakerTokenAmount = await this._orderFilledCancelledLazyStore.getFilledTakerAmountAsync(orderHash);
const cancelledTakerTokenAmount = await this._orderFilledCancelledLazyStore.getCancelledTakerAmountAsync( const cancelledTakerTokenAmount = await this._orderFilledCancelledLazyStore.getCancelledTakerAmountAsync(
@ -104,17 +113,20 @@ export class OrderStateUtils {
const totalMakerTokenAmount = signedOrder.makerTokenAmount; const totalMakerTokenAmount = signedOrder.makerTokenAmount;
const totalTakerTokenAmount = signedOrder.takerTokenAmount; const totalTakerTokenAmount = signedOrder.takerTokenAmount;
const remainingTakerTokenAmount = totalTakerTokenAmount.minus(unavailableTakerTokenAmount); const remainingTakerTokenAmount = totalTakerTokenAmount.minus(unavailableTakerTokenAmount);
const remainingMakerTokenAmount = remainingTakerTokenAmount.times(totalMakerTokenAmount) const remainingMakerTokenAmount = remainingTakerTokenAmount
.times(totalMakerTokenAmount)
.dividedToIntegerBy(totalTakerTokenAmount); .dividedToIntegerBy(totalTakerTokenAmount);
const transferrableMakerTokenAmount = BigNumber.min([makerProxyAllowance, makerBalance]); const transferrableMakerTokenAmount = BigNumber.min([makerProxyAllowance, makerBalance]);
const transferrableFeeTokenAmount = BigNumber.min([makerFeeProxyAllowance, makerFeeBalance]); const transferrableFeeTokenAmount = BigNumber.min([makerFeeProxyAllowance, makerFeeBalance]);
const isMakerTokenZRX = signedOrder.makerTokenAddress === zrxTokenAddress; const isMakerTokenZRX = signedOrder.makerTokenAddress === zrxTokenAddress;
const remainingFillableCalculator = new RemainingFillableCalculator(signedOrder, const remainingFillableCalculator = new RemainingFillableCalculator(
signedOrder,
isMakerTokenZRX, isMakerTokenZRX,
transferrableMakerTokenAmount, transferrableMakerTokenAmount,
transferrableFeeTokenAmount, transferrableFeeTokenAmount,
remainingMakerTokenAmount); remainingMakerTokenAmount,
);
const remainingFillableMakerTokenAmount = remainingFillableCalculator.computeRemainingMakerFillable(); const remainingFillableMakerTokenAmount = remainingFillableCalculator.computeRemainingMakerFillable();
const remainingFillableTakerTokenAmount = remainingFillableCalculator.computeRemainingTakerFillable(); const remainingFillableTakerTokenAmount = remainingFillableCalculator.computeRemainingTakerFillable();
const orderRelevantState = { const orderRelevantState = {

View File

@ -12,7 +12,9 @@ import {ExchangeTransferSimulator} from './exchange_transfer_simulator';
export class OrderValidationUtils { export class OrderValidationUtils {
private _exchangeWrapper: ExchangeWrapper; private _exchangeWrapper: ExchangeWrapper;
public static validateCancelOrderThrowIfInvalid( public static validateCancelOrderThrowIfInvalid(
order: Order, cancelTakerTokenAmount: BigNumber, unavailableTakerTokenAmount: BigNumber, order: Order,
cancelTakerTokenAmount: BigNumber,
unavailableTakerTokenAmount: BigNumber,
): void { ): void {
if (cancelTakerTokenAmount.eq(0)) { if (cancelTakerTokenAmount.eq(0)) {
throw new Error(ExchangeContractErrs.OrderCancelAmountZero); throw new Error(ExchangeContractErrs.OrderCancelAmountZero);
@ -26,8 +28,11 @@ export class OrderValidationUtils {
} }
} }
public static async validateFillOrderBalancesAllowancesThrowIfInvalidAsync( public static async validateFillOrderBalancesAllowancesThrowIfInvalidAsync(
exchangeTradeEmulator: ExchangeTransferSimulator, signedOrder: SignedOrder, exchangeTradeEmulator: ExchangeTransferSimulator,
fillTakerTokenAmount: BigNumber, senderAddress: string, zrxTokenAddress: string, signedOrder: SignedOrder,
fillTakerTokenAmount: BigNumber,
senderAddress: string,
zrxTokenAddress: string,
): Promise<void> { ): Promise<void> {
const fillMakerTokenAmount = OrderValidationUtils._getPartialAmount( const fillMakerTokenAmount = OrderValidationUtils._getPartialAmount(
fillTakerTokenAmount, fillTakerTokenAmount,
@ -35,12 +40,20 @@ export class OrderValidationUtils {
signedOrder.makerTokenAmount, signedOrder.makerTokenAmount,
); );
await exchangeTradeEmulator.transferFromAsync( await exchangeTradeEmulator.transferFromAsync(
signedOrder.makerTokenAddress, signedOrder.maker, senderAddress, fillMakerTokenAmount, signedOrder.makerTokenAddress,
TradeSide.Maker, TransferType.Trade, signedOrder.maker,
senderAddress,
fillMakerTokenAmount,
TradeSide.Maker,
TransferType.Trade,
); );
await exchangeTradeEmulator.transferFromAsync( await exchangeTradeEmulator.transferFromAsync(
signedOrder.takerTokenAddress, senderAddress, signedOrder.maker, fillTakerTokenAmount, signedOrder.takerTokenAddress,
TradeSide.Taker, TransferType.Trade, senderAddress,
signedOrder.maker,
fillTakerTokenAmount,
TradeSide.Taker,
TransferType.Trade,
); );
const makerFeeAmount = OrderValidationUtils._getPartialAmount( const makerFeeAmount = OrderValidationUtils._getPartialAmount(
fillTakerTokenAmount, fillTakerTokenAmount,
@ -48,7 +61,11 @@ export class OrderValidationUtils {
signedOrder.makerFee, signedOrder.makerFee,
); );
await exchangeTradeEmulator.transferFromAsync( await exchangeTradeEmulator.transferFromAsync(
zrxTokenAddress, signedOrder.maker, signedOrder.feeRecipient, makerFeeAmount, TradeSide.Maker, zrxTokenAddress,
signedOrder.maker,
signedOrder.feeRecipient,
makerFeeAmount,
TradeSide.Maker,
TransferType.Fee, TransferType.Fee,
); );
const takerFeeAmount = OrderValidationUtils._getPartialAmount( const takerFeeAmount = OrderValidationUtils._getPartialAmount(
@ -57,12 +74,17 @@ export class OrderValidationUtils {
signedOrder.takerFee, signedOrder.takerFee,
); );
await exchangeTradeEmulator.transferFromAsync( await exchangeTradeEmulator.transferFromAsync(
zrxTokenAddress, senderAddress, signedOrder.feeRecipient, takerFeeAmount, TradeSide.Taker, zrxTokenAddress,
senderAddress,
signedOrder.feeRecipient,
takerFeeAmount,
TradeSide.Taker,
TransferType.Fee, TransferType.Fee,
); );
} }
private static _validateRemainingFillAmountNotZeroOrThrow( private static _validateRemainingFillAmountNotZeroOrThrow(
takerTokenAmount: BigNumber, unavailableTakerTokenAmount: BigNumber, takerTokenAmount: BigNumber,
unavailableTakerTokenAmount: BigNumber,
) { ) {
if (takerTokenAmount.eq(unavailableTakerTokenAmount)) { if (takerTokenAmount.eq(unavailableTakerTokenAmount)) {
throw new Error(ExchangeContractErrs.OrderRemainingFillAmountZero); throw new Error(ExchangeContractErrs.OrderRemainingFillAmountZero);
@ -74,8 +96,7 @@ export class OrderValidationUtils {
throw new Error(ExchangeContractErrs.OrderFillExpired); throw new Error(ExchangeContractErrs.OrderFillExpired);
} }
} }
private static _getPartialAmount(numerator: BigNumber, denominator: BigNumber, private static _getPartialAmount(numerator: BigNumber, denominator: BigNumber, target: BigNumber): BigNumber {
target: BigNumber): BigNumber {
const fillMakerTokenAmount = numerator const fillMakerTokenAmount = numerator
.mul(target) .mul(target)
.div(denominator) .div(denominator)
@ -86,12 +107,16 @@ export class OrderValidationUtils {
this._exchangeWrapper = exchangeWrapper; this._exchangeWrapper = exchangeWrapper;
} }
public async validateOrderFillableOrThrowAsync( public async validateOrderFillableOrThrowAsync(
exchangeTradeEmulator: ExchangeTransferSimulator, signedOrder: SignedOrder, zrxTokenAddress: string, exchangeTradeEmulator: ExchangeTransferSimulator,
expectedFillTakerTokenAmount?: BigNumber): Promise<void> { signedOrder: SignedOrder,
zrxTokenAddress: string,
expectedFillTakerTokenAmount?: BigNumber,
): Promise<void> {
const orderHash = utils.getOrderHashHex(signedOrder); const orderHash = utils.getOrderHashHex(signedOrder);
const unavailableTakerTokenAmount = await this._exchangeWrapper.getUnavailableTakerAmountAsync(orderHash); const unavailableTakerTokenAmount = await this._exchangeWrapper.getUnavailableTakerAmountAsync(orderHash);
OrderValidationUtils._validateRemainingFillAmountNotZeroOrThrow( OrderValidationUtils._validateRemainingFillAmountNotZeroOrThrow(
signedOrder.takerTokenAmount, unavailableTakerTokenAmount, signedOrder.takerTokenAmount,
unavailableTakerTokenAmount,
); );
OrderValidationUtils._validateOrderNotExpiredOrThrow(signedOrder.expirationUnixTimestampSec); OrderValidationUtils._validateOrderNotExpiredOrThrow(signedOrder.expirationUnixTimestampSec);
let fillTakerTokenAmount = signedOrder.takerTokenAmount.minus(unavailableTakerTokenAmount); let fillTakerTokenAmount = signedOrder.takerTokenAmount.minus(unavailableTakerTokenAmount);
@ -104,8 +129,12 @@ export class OrderValidationUtils {
signedOrder.makerTokenAmount, signedOrder.makerTokenAmount,
); );
await exchangeTradeEmulator.transferFromAsync( await exchangeTradeEmulator.transferFromAsync(
signedOrder.makerTokenAddress, signedOrder.maker, signedOrder.taker, fillMakerTokenAmount, signedOrder.makerTokenAddress,
TradeSide.Maker, TransferType.Trade, signedOrder.maker,
signedOrder.taker,
fillMakerTokenAmount,
TradeSide.Maker,
TransferType.Trade,
); );
const makerFeeAmount = OrderValidationUtils._getPartialAmount( const makerFeeAmount = OrderValidationUtils._getPartialAmount(
fillTakerTokenAmount, fillTakerTokenAmount,
@ -113,14 +142,21 @@ export class OrderValidationUtils {
signedOrder.makerFee, signedOrder.makerFee,
); );
await exchangeTradeEmulator.transferFromAsync( await exchangeTradeEmulator.transferFromAsync(
zrxTokenAddress, signedOrder.maker, signedOrder.feeRecipient, makerFeeAmount, zrxTokenAddress,
TradeSide.Maker, TransferType.Fee, signedOrder.maker,
signedOrder.feeRecipient,
makerFeeAmount,
TradeSide.Maker,
TransferType.Fee,
); );
} }
public async validateFillOrderThrowIfInvalidAsync( public async validateFillOrderThrowIfInvalidAsync(
exchangeTradeEmulator: ExchangeTransferSimulator, signedOrder: SignedOrder, exchangeTradeEmulator: ExchangeTransferSimulator,
fillTakerTokenAmount: BigNumber, takerAddress: string, signedOrder: SignedOrder,
zrxTokenAddress: string): Promise<BigNumber> { fillTakerTokenAmount: BigNumber,
takerAddress: string,
zrxTokenAddress: string,
): Promise<BigNumber> {
if (fillTakerTokenAmount.eq(0)) { if (fillTakerTokenAmount.eq(0)) {
throw new Error(ExchangeContractErrs.OrderFillAmountZero); throw new Error(ExchangeContractErrs.OrderFillAmountZero);
} }
@ -130,22 +166,29 @@ export class OrderValidationUtils {
} }
const unavailableTakerTokenAmount = await this._exchangeWrapper.getUnavailableTakerAmountAsync(orderHash); const unavailableTakerTokenAmount = await this._exchangeWrapper.getUnavailableTakerAmountAsync(orderHash);
OrderValidationUtils._validateRemainingFillAmountNotZeroOrThrow( OrderValidationUtils._validateRemainingFillAmountNotZeroOrThrow(
signedOrder.takerTokenAmount, unavailableTakerTokenAmount, signedOrder.takerTokenAmount,
unavailableTakerTokenAmount,
); );
if (signedOrder.taker !== constants.NULL_ADDRESS && signedOrder.taker !== takerAddress) { if (signedOrder.taker !== constants.NULL_ADDRESS && signedOrder.taker !== takerAddress) {
throw new Error(ExchangeContractErrs.TransactionSenderIsNotFillOrderTaker); throw new Error(ExchangeContractErrs.TransactionSenderIsNotFillOrderTaker);
} }
OrderValidationUtils._validateOrderNotExpiredOrThrow(signedOrder.expirationUnixTimestampSec); OrderValidationUtils._validateOrderNotExpiredOrThrow(signedOrder.expirationUnixTimestampSec);
const remainingTakerTokenAmount = signedOrder.takerTokenAmount.minus(unavailableTakerTokenAmount); const remainingTakerTokenAmount = signedOrder.takerTokenAmount.minus(unavailableTakerTokenAmount);
const filledTakerTokenAmount = remainingTakerTokenAmount.lessThan(fillTakerTokenAmount) ? const filledTakerTokenAmount = remainingTakerTokenAmount.lessThan(fillTakerTokenAmount)
remainingTakerTokenAmount : ? remainingTakerTokenAmount
fillTakerTokenAmount; : fillTakerTokenAmount;
await OrderValidationUtils.validateFillOrderBalancesAllowancesThrowIfInvalidAsync( await OrderValidationUtils.validateFillOrderBalancesAllowancesThrowIfInvalidAsync(
exchangeTradeEmulator, signedOrder, filledTakerTokenAmount, takerAddress, zrxTokenAddress, exchangeTradeEmulator,
signedOrder,
filledTakerTokenAmount,
takerAddress,
zrxTokenAddress,
); );
const wouldRoundingErrorOccur = await this._exchangeWrapper.isRoundingErrorAsync( const wouldRoundingErrorOccur = await this._exchangeWrapper.isRoundingErrorAsync(
filledTakerTokenAmount, signedOrder.takerTokenAmount, signedOrder.makerTokenAmount, filledTakerTokenAmount,
signedOrder.takerTokenAmount,
signedOrder.makerTokenAmount,
); );
if (wouldRoundingErrorOccur) { if (wouldRoundingErrorOccur) {
throw new Error(ExchangeContractErrs.OrderFillRoundingError); throw new Error(ExchangeContractErrs.OrderFillRoundingError);
@ -153,10 +196,18 @@ export class OrderValidationUtils {
return filledTakerTokenAmount; return filledTakerTokenAmount;
} }
public async validateFillOrKillOrderThrowIfInvalidAsync( public async validateFillOrKillOrderThrowIfInvalidAsync(
exchangeTradeEmulator: ExchangeTransferSimulator, signedOrder: SignedOrder, exchangeTradeEmulator: ExchangeTransferSimulator,
fillTakerTokenAmount: BigNumber, takerAddress: string, zrxTokenAddress: string): Promise<void> { signedOrder: SignedOrder,
fillTakerTokenAmount: BigNumber,
takerAddress: string,
zrxTokenAddress: string,
): Promise<void> {
const filledTakerTokenAmount = await this.validateFillOrderThrowIfInvalidAsync( const filledTakerTokenAmount = await this.validateFillOrderThrowIfInvalidAsync(
exchangeTradeEmulator, signedOrder, fillTakerTokenAmount, takerAddress, zrxTokenAddress, exchangeTradeEmulator,
signedOrder,
fillTakerTokenAmount,
takerAddress,
zrxTokenAddress,
); );
if (filledTakerTokenAmount !== fillTakerTokenAmount) { if (filledTakerTokenAmount !== fillTakerTokenAmount) {
throw new Error(ExchangeContractErrs.InsufficientRemainingFillAmount); throw new Error(ExchangeContractErrs.InsufficientRemainingFillAmount);

View File

@ -11,7 +11,8 @@ export const signatureUtils = {
msgHashBuff, msgHashBuff,
signature.v, signature.v,
ethUtil.toBuffer(signature.r), ethUtil.toBuffer(signature.r),
ethUtil.toBuffer(signature.s)); ethUtil.toBuffer(signature.s),
);
const retrievedAddress = ethUtil.bufferToHex(ethUtil.pubToAddress(pubKey)); const retrievedAddress = ethUtil.bufferToHex(ethUtil.pubToAddress(pubKey));
return retrievedAddress === signerAddress; return retrievedAddress === signerAddress;
} catch (err) { } catch (err) {

View File

@ -37,11 +37,26 @@ export const utils = {
{ value: order.makerTokenAddress, type: SolidityTypes.Address }, { value: order.makerTokenAddress, type: SolidityTypes.Address },
{ value: order.takerTokenAddress, type: SolidityTypes.Address }, { value: order.takerTokenAddress, type: SolidityTypes.Address },
{ value: order.feeRecipient, type: SolidityTypes.Address }, { value: order.feeRecipient, type: SolidityTypes.Address },
{value: utils.bigNumberToBN(order.makerTokenAmount), type: SolidityTypes.Uint256}, {
{value: utils.bigNumberToBN(order.takerTokenAmount), type: SolidityTypes.Uint256}, value: utils.bigNumberToBN(order.makerTokenAmount),
{value: utils.bigNumberToBN(order.makerFee), type: SolidityTypes.Uint256}, type: SolidityTypes.Uint256,
{value: utils.bigNumberToBN(order.takerFee), type: SolidityTypes.Uint256}, },
{value: utils.bigNumberToBN(order.expirationUnixTimestampSec), type: SolidityTypes.Uint256}, {
value: utils.bigNumberToBN(order.takerTokenAmount),
type: SolidityTypes.Uint256,
},
{
value: utils.bigNumberToBN(order.makerFee),
type: SolidityTypes.Uint256,
},
{
value: utils.bigNumberToBN(order.takerFee),
type: SolidityTypes.Uint256,
},
{
value: utils.bigNumberToBN(order.expirationUnixTimestampSec),
type: SolidityTypes.Uint256,
},
{ value: utils.bigNumberToBN(order.salt), type: SolidityTypes.Uint256 }, { value: utils.bigNumberToBN(order.salt), type: SolidityTypes.Uint256 },
]; ];
const types = _.map(orderParts, o => o.type); const types = _.map(orderParts, o => o.type);

View File

@ -41,11 +41,11 @@ describe('ZeroEx library', () => {
// Check that all nested web3 wrapper instances return the updated provider // Check that all nested web3 wrapper instances return the updated provider
const nestedWeb3WrapperProvider = (zeroEx as any)._web3Wrapper.getCurrentProvider(); const nestedWeb3WrapperProvider = (zeroEx as any)._web3Wrapper.getCurrentProvider();
expect((nestedWeb3WrapperProvider).zeroExTestId).to.be.a('number'); expect(nestedWeb3WrapperProvider.zeroExTestId).to.be.a('number');
const exchangeWeb3WrapperProvider = (zeroEx.exchange as any)._web3Wrapper.getCurrentProvider(); const exchangeWeb3WrapperProvider = (zeroEx.exchange as any)._web3Wrapper.getCurrentProvider();
expect((exchangeWeb3WrapperProvider).zeroExTestId).to.be.a('number'); expect(exchangeWeb3WrapperProvider.zeroExTestId).to.be.a('number');
const tokenRegistryWeb3WrapperProvider = (zeroEx.tokenRegistry as any)._web3Wrapper.getCurrentProvider(); const tokenRegistryWeb3WrapperProvider = (zeroEx.tokenRegistry as any)._web3Wrapper.getCurrentProvider();
expect((tokenRegistryWeb3WrapperProvider).zeroExTestId).to.be.a('number'); expect(tokenRegistryWeb3WrapperProvider.zeroExTestId).to.be.a('number');
}); });
}); });
describe('#isValidSignature', () => { describe('#isValidSignature', () => {
@ -58,21 +58,24 @@ describe('ZeroEx library', () => {
s: '0x40349190569279751135161d22529dc25add4f6069af05be04cacbda2ace2254', s: '0x40349190569279751135161d22529dc25add4f6069af05be04cacbda2ace2254',
}; };
const address = '0x5409ed021d9299bf6814279a6a1411a7e866a631'; const address = '0x5409ed021d9299bf6814279a6a1411a7e866a631';
it('should return false if the data doesn\'t pertain to the signature & address', async () => { it("should return false if the data doesn't pertain to the signature & address", async () => {
expect(ZeroEx.isValidSignature('0x0', signature, address)).to.be.false(); expect(ZeroEx.isValidSignature('0x0', signature, address)).to.be.false();
return expect( return expect(
(zeroEx.exchange as any)._isValidSignatureUsingContractCallAsync('0x0', signature, address), (zeroEx.exchange as any)._isValidSignatureUsingContractCallAsync('0x0', signature, address),
).to.become(false); ).to.become(false);
}); });
it('should return false if the address doesn\'t pertain to the signature & data', async () => { it("should return false if the address doesn't pertain to the signature & data", async () => {
const validUnrelatedAddress = '0x8b0292b11a196601ed2ce54b665cafeca0347d42'; const validUnrelatedAddress = '0x8b0292b11a196601ed2ce54b665cafeca0347d42';
expect(ZeroEx.isValidSignature(dataHex, signature, validUnrelatedAddress)).to.be.false(); expect(ZeroEx.isValidSignature(dataHex, signature, validUnrelatedAddress)).to.be.false();
return expect( return expect(
(zeroEx.exchange as any)._isValidSignatureUsingContractCallAsync(dataHex, signature, (zeroEx.exchange as any)._isValidSignatureUsingContractCallAsync(
validUnrelatedAddress), dataHex,
signature,
validUnrelatedAddress,
),
).to.become(false); ).to.become(false);
}); });
it('should return false if the signature doesn\'t pertain to the dataHex & address', async () => { it("should return false if the signature doesn't pertain to the dataHex & address", async () => {
const wrongSignature = _.assign({}, signature, { v: 28 }); const wrongSignature = _.assign({}, signature, { v: 28 });
expect(ZeroEx.isValidSignature(dataHex, wrongSignature, address)).to.be.false(); expect(ZeroEx.isValidSignature(dataHex, wrongSignature, address)).to.be.false();
return expect( return expect(
@ -117,8 +120,9 @@ describe('ZeroEx library', () => {
it('should throw if invalid baseUnit amount supplied as argument', () => { it('should throw if invalid baseUnit amount supplied as argument', () => {
const invalidBaseUnitAmount = new BigNumber(1000000000.4); const invalidBaseUnitAmount = new BigNumber(1000000000.4);
const decimals = 6; const decimals = 6;
expect(() => ZeroEx.toUnitAmount(invalidBaseUnitAmount, decimals)) expect(() => ZeroEx.toUnitAmount(invalidBaseUnitAmount, decimals)).to.throw(
.to.throw('amount should be in baseUnits (no decimals), found value: 1000000000.4'); 'amount should be in baseUnits (no decimals), found value: 1000000000.4',
);
}); });
it('Should return the expected unit amount for the decimals passed in', () => { it('Should return the expected unit amount for the decimals passed in', () => {
const baseUnitAmount = new BigNumber(1000000000); const baseUnitAmount = new BigNumber(1000000000);
@ -139,8 +143,9 @@ describe('ZeroEx library', () => {
it('should throw if unitAmount has more decimals then specified as the max decimal precision', () => { it('should throw if unitAmount has more decimals then specified as the max decimal precision', () => {
const unitAmount = new BigNumber(0.823091); const unitAmount = new BigNumber(0.823091);
const decimals = 5; const decimals = 5;
expect(() => ZeroEx.toBaseUnitAmount(unitAmount, decimals)) expect(() => ZeroEx.toBaseUnitAmount(unitAmount, decimals)).to.throw(
.to.throw('Invalid unit amount: 0.823091 - Too many decimal places'); 'Invalid unit amount: 0.823091 - Too many decimal places',
);
}); });
}); });
describe('#getOrderHashHex', () => { describe('#getOrderHashHex', () => {
@ -167,10 +172,11 @@ describe('ZeroEx library', () => {
it('throws a readable error message if taker format is invalid', async () => { it('throws a readable error message if taker format is invalid', async () => {
const orderWithInvalidtakerFormat = { const orderWithInvalidtakerFormat = {
...order, ...order,
taker: null as any as string, taker: (null as any) as string,
}; };
// tslint:disable-next-line:max-line-length // 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'; 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); expect(() => ZeroEx.getOrderHashHex(orderWithInvalidtakerFormat)).to.throw(expectedErrorMessage);
}); });
}); });
@ -199,15 +205,15 @@ describe('ZeroEx library', () => {
it('should return the correct ECSignature for signatureHex concatenated as R + S + V', async () => { it('should return the correct ECSignature for signatureHex concatenated as R + S + V', async () => {
const orderHash = '0x34decbedc118904df65f379a175bb39ca18209d6ce41d5ed549d54e6e0a95004'; const orderHash = '0x34decbedc118904df65f379a175bb39ca18209d6ce41d5ed549d54e6e0a95004';
// tslint:disable-next-line: max-line-length // tslint:disable-next-line: max-line-length
const signature = '0x22109d11d79cb8bf96ed88625e1cd9558800c4073332a9a02857499883ee5ce3050aa3cc1f2c435e67e114cdce54b9527b4f50548342401bc5d2b77adbdacb021b'; const signature =
'0x22109d11d79cb8bf96ed88625e1cd9558800c4073332a9a02857499883ee5ce3050aa3cc1f2c435e67e114cdce54b9527b4f50548342401bc5d2b77adbdacb021b';
const expectedECSignature = { const expectedECSignature = {
v: 27, v: 27,
r: '0x22109d11d79cb8bf96ed88625e1cd9558800c4073332a9a02857499883ee5ce3', r: '0x22109d11d79cb8bf96ed88625e1cd9558800c4073332a9a02857499883ee5ce3',
s: '0x050aa3cc1f2c435e67e114cdce54b9527b4f50548342401bc5d2b77adbdacb02', s: '0x050aa3cc1f2c435e67e114cdce54b9527b4f50548342401bc5d2b77adbdacb02',
}; };
stubs = [ stubs = [
Sinon.stub((zeroEx as any)._web3Wrapper, 'signTransactionAsync') Sinon.stub((zeroEx as any)._web3Wrapper, 'signTransactionAsync').returns(Promise.resolve(signature)),
.returns(Promise.resolve(signature)),
Sinon.stub(ZeroEx, 'isValidSignature').returns(true), Sinon.stub(ZeroEx, 'isValidSignature').returns(true),
]; ];
@ -217,15 +223,15 @@ describe('ZeroEx library', () => {
it('should return the correct ECSignature for signatureHex concatenated as V + R + S', async () => { it('should return the correct ECSignature for signatureHex concatenated as V + R + S', async () => {
const orderHash = '0xc793e33ffded933b76f2f48d9aa3339fc090399d5e7f5dec8d3660f5480793f7'; const orderHash = '0xc793e33ffded933b76f2f48d9aa3339fc090399d5e7f5dec8d3660f5480793f7';
// tslint:disable-next-line: max-line-length // tslint:disable-next-line: max-line-length
const signature = '0x1bc80bedc6756722672753413efdd749b5adbd4fd552595f59c13427407ee9aee02dea66f25a608bbae457e020fb6decb763deb8b7192abab624997242da248960'; const signature =
'0x1bc80bedc6756722672753413efdd749b5adbd4fd552595f59c13427407ee9aee02dea66f25a608bbae457e020fb6decb763deb8b7192abab624997242da248960';
const expectedECSignature = { const expectedECSignature = {
v: 27, v: 27,
r: '0xc80bedc6756722672753413efdd749b5adbd4fd552595f59c13427407ee9aee0', r: '0xc80bedc6756722672753413efdd749b5adbd4fd552595f59c13427407ee9aee0',
s: '0x2dea66f25a608bbae457e020fb6decb763deb8b7192abab624997242da248960', s: '0x2dea66f25a608bbae457e020fb6decb763deb8b7192abab624997242da248960',
}; };
stubs = [ stubs = [
Sinon.stub((zeroEx as any)._web3Wrapper, 'signTransactionAsync') Sinon.stub((zeroEx as any)._web3Wrapper, 'signTransactionAsync').returns(Promise.resolve(signature)),
.returns(Promise.resolve(signature)),
Sinon.stub(ZeroEx, 'isValidSignature').returns(true), Sinon.stub(ZeroEx, 'isValidSignature').returns(true),
]; ];
@ -271,8 +277,9 @@ describe('ZeroEx library', () => {
networkId: constants.TESTRPC_NETWORK_ID, networkId: constants.TESTRPC_NETWORK_ID,
}; };
const zeroExWithWrongTokenRegistryAddress = new ZeroEx(web3.currentProvider, zeroExConfig); const zeroExWithWrongTokenRegistryAddress = new ZeroEx(web3.currentProvider, zeroExConfig);
expect(zeroExWithWrongTokenRegistryAddress.tokenRegistry.getContractAddress()) expect(zeroExWithWrongTokenRegistryAddress.tokenRegistry.getContractAddress()).to.be.equal(
.to.be.equal(ZeroEx.NULL_ADDRESS); ZeroEx.NULL_ADDRESS,
);
}); });
}); });
}); });

View File

@ -19,22 +19,25 @@ describe('Assertion library', () => {
it('throws when address is invalid', async () => { it('throws when address is invalid', async () => {
const address = '0xdeadbeef'; const address = '0xdeadbeef';
const varName = 'address'; const varName = 'address';
return expect(assert.isSenderAddressAsync(varName, address, (zeroEx as any)._web3Wrapper)) return expect(
.to.be.rejectedWith(`Expected ${varName} to be of type ETHAddressHex, encountered: ${address}`); assert.isSenderAddressAsync(varName, address, (zeroEx as any)._web3Wrapper),
).to.be.rejectedWith(`Expected ${varName} to be of type ETHAddressHex, encountered: ${address}`);
}); });
it('throws when address is unavailable', async () => { it('throws when address is unavailable', async () => {
const validUnrelatedAddress = '0x8b0292b11a196601eddce54b665cafeca0347d42'; const validUnrelatedAddress = '0x8b0292b11a196601eddce54b665cafeca0347d42';
const varName = 'address'; const varName = 'address';
return expect(assert.isSenderAddressAsync(varName, validUnrelatedAddress, (zeroEx as any)._web3Wrapper)) return expect(
.to.be.rejectedWith( assert.isSenderAddressAsync(varName, validUnrelatedAddress, (zeroEx as any)._web3Wrapper),
).to.be.rejectedWith(
`Specified ${varName} ${validUnrelatedAddress} isn't available through the supplied web3 provider`, `Specified ${varName} ${validUnrelatedAddress} isn't available through the supplied web3 provider`,
); );
}); });
it('doesn\'t throw if address is available', async () => { it("doesn't throw if address is available", async () => {
const availableAddress = (await zeroEx.getAvailableAddressesAsync())[0]; const availableAddress = (await zeroEx.getAvailableAddressesAsync())[0];
const varName = 'address'; const varName = 'address';
return expect(assert.isSenderAddressAsync(varName, availableAddress, (zeroEx as any)._web3Wrapper)) return expect(
.to.become(undefined); assert.isSenderAddressAsync(varName, availableAddress, (zeroEx as any)._web3Wrapper),
).to.become(undefined);
}); });
}); });
}); });

View File

@ -167,10 +167,12 @@ describe('EtherTokenWrapper', () => {
done(); done();
}; };
await zeroEx.etherToken.depositAsync(etherTokenAddress, transferAmount, addressWithETH); await zeroEx.etherToken.depositAsync(etherTokenAddress, transferAmount, addressWithETH);
zeroEx.etherToken.subscribe( zeroEx.etherToken.subscribe(etherTokenAddress, EtherTokenEvents.Transfer, indexFilterValues, callback);
etherTokenAddress, EtherTokenEvents.Transfer, indexFilterValues, callback);
await zeroEx.token.transferAsync( await zeroEx.token.transferAsync(
etherTokenAddress, addressWithETH, addressWithoutFunds, transferAmount, etherTokenAddress,
addressWithETH,
addressWithoutFunds,
transferAmount,
); );
})().catch(done); })().catch(done);
}); });
@ -186,10 +188,12 @@ describe('EtherTokenWrapper', () => {
expect(args._value).to.be.bignumber.equal(allowanceAmount); expect(args._value).to.be.bignumber.equal(allowanceAmount);
done(); done();
}; };
zeroEx.etherToken.subscribe( zeroEx.etherToken.subscribe(etherTokenAddress, EtherTokenEvents.Approval, indexFilterValues, callback);
etherTokenAddress, EtherTokenEvents.Approval, indexFilterValues, callback);
await zeroEx.token.setAllowanceAsync( await zeroEx.token.setAllowanceAsync(
etherTokenAddress, addressWithETH, addressWithoutFunds, allowanceAmount, etherTokenAddress,
addressWithETH,
addressWithoutFunds,
allowanceAmount,
); );
})().catch(done); })().catch(done);
}); });
@ -204,11 +208,8 @@ describe('EtherTokenWrapper', () => {
expect(args._value).to.be.bignumber.equal(depositAmount); expect(args._value).to.be.bignumber.equal(depositAmount);
done(); done();
}; };
zeroEx.etherToken.subscribe( zeroEx.etherToken.subscribe(etherTokenAddress, EtherTokenEvents.Deposit, indexFilterValues, callback);
etherTokenAddress, EtherTokenEvents.Deposit, indexFilterValues, callback); await zeroEx.etherToken.depositAsync(etherTokenAddress, depositAmount, addressWithETH);
await zeroEx.etherToken.depositAsync(
etherTokenAddress, depositAmount, addressWithETH,
);
})().catch(done); })().catch(done);
}); });
it('Should receive the Withdrawal event when ether is being withdrawn', (done: DoneCallback) => { it('Should receive the Withdrawal event when ether is being withdrawn', (done: DoneCallback) => {
@ -222,14 +223,14 @@ describe('EtherTokenWrapper', () => {
expect(args._value).to.be.bignumber.equal(depositAmount); expect(args._value).to.be.bignumber.equal(depositAmount);
done(); done();
}; };
await zeroEx.etherToken.depositAsync( await zeroEx.etherToken.depositAsync(etherTokenAddress, depositAmount, addressWithETH);
etherTokenAddress, depositAmount, addressWithETH,
);
zeroEx.etherToken.subscribe( zeroEx.etherToken.subscribe(
etherTokenAddress, EtherTokenEvents.Withdrawal, indexFilterValues, callback); etherTokenAddress,
await zeroEx.etherToken.withdrawAsync( EtherTokenEvents.Withdrawal,
etherTokenAddress, withdrawalAmount, addressWithETH, indexFilterValues,
callback,
); );
await zeroEx.etherToken.withdrawAsync(etherTokenAddress, withdrawalAmount, addressWithETH);
})().catch(done); })().catch(done);
}); });
it('should cancel outstanding subscriptions when ZeroEx.setProvider is called', (done: DoneCallback) => { it('should cancel outstanding subscriptions when ZeroEx.setProvider is called', (done: DoneCallback) => {
@ -238,7 +239,10 @@ describe('EtherTokenWrapper', () => {
done(new Error('Expected this subscription to have been cancelled')); done(new Error('Expected this subscription to have been cancelled'));
}; };
zeroEx.etherToken.subscribe( zeroEx.etherToken.subscribe(
etherTokenAddress, EtherTokenEvents.Transfer, indexFilterValues, callbackNeverToBeCalled, etherTokenAddress,
EtherTokenEvents.Transfer,
indexFilterValues,
callbackNeverToBeCalled,
); );
const callbackToBeCalled = (err: Error, logEvent: DecodedLogEvent<ApprovalContractEventArgs>) => { const callbackToBeCalled = (err: Error, logEvent: DecodedLogEvent<ApprovalContractEventArgs>) => {
done(); done();
@ -247,10 +251,16 @@ describe('EtherTokenWrapper', () => {
zeroEx.setProvider(newProvider, constants.TESTRPC_NETWORK_ID); zeroEx.setProvider(newProvider, constants.TESTRPC_NETWORK_ID);
await zeroEx.etherToken.depositAsync(etherTokenAddress, transferAmount, addressWithETH); await zeroEx.etherToken.depositAsync(etherTokenAddress, transferAmount, addressWithETH);
zeroEx.etherToken.subscribe( zeroEx.etherToken.subscribe(
etherTokenAddress, EtherTokenEvents.Transfer, indexFilterValues, callbackToBeCalled, etherTokenAddress,
EtherTokenEvents.Transfer,
indexFilterValues,
callbackToBeCalled,
); );
await zeroEx.token.transferAsync( await zeroEx.token.transferAsync(
etherTokenAddress, addressWithETH, addressWithoutFunds, transferAmount, etherTokenAddress,
addressWithETH,
addressWithoutFunds,
transferAmount,
); );
})().catch(done); })().catch(done);
}); });
@ -261,10 +271,17 @@ describe('EtherTokenWrapper', () => {
}; };
await zeroEx.etherToken.depositAsync(etherTokenAddress, transferAmount, addressWithETH); await zeroEx.etherToken.depositAsync(etherTokenAddress, transferAmount, addressWithETH);
const subscriptionToken = zeroEx.etherToken.subscribe( const subscriptionToken = zeroEx.etherToken.subscribe(
etherTokenAddress, EtherTokenEvents.Transfer, indexFilterValues, callbackNeverToBeCalled); etherTokenAddress,
EtherTokenEvents.Transfer,
indexFilterValues,
callbackNeverToBeCalled,
);
zeroEx.etherToken.unsubscribe(subscriptionToken); zeroEx.etherToken.unsubscribe(subscriptionToken);
await zeroEx.token.transferAsync( await zeroEx.token.transferAsync(
etherTokenAddress, addressWithETH, addressWithoutFunds, transferAmount, etherTokenAddress,
addressWithETH,
addressWithoutFunds,
transferAmount,
); );
done(); done();
})().catch(done); })().catch(done);
@ -291,7 +308,10 @@ describe('EtherTokenWrapper', () => {
const eventName = EtherTokenEvents.Approval; const eventName = EtherTokenEvents.Approval;
const indexFilterValues = {}; const indexFilterValues = {};
const logs = await zeroEx.etherToken.getLogsAsync<ApprovalContractEventArgs>( const logs = await zeroEx.etherToken.getLogsAsync<ApprovalContractEventArgs>(
etherTokenAddress, eventName, blockRange, indexFilterValues, etherTokenAddress,
eventName,
blockRange,
indexFilterValues,
); );
expect(logs).to.have.length(1); expect(logs).to.have.length(1);
const args = logs[0].args; const args = logs[0].args;
@ -305,7 +325,10 @@ describe('EtherTokenWrapper', () => {
const eventName = EtherTokenEvents.Deposit; const eventName = EtherTokenEvents.Deposit;
const indexFilterValues = {}; const indexFilterValues = {};
const logs = await zeroEx.etherToken.getLogsAsync<DepositContractEventArgs>( const logs = await zeroEx.etherToken.getLogsAsync<DepositContractEventArgs>(
etherTokenAddress, eventName, blockRange, indexFilterValues, etherTokenAddress,
eventName,
blockRange,
indexFilterValues,
); );
expect(logs).to.have.length(1); expect(logs).to.have.length(1);
const args = logs[0].args; const args = logs[0].args;
@ -319,7 +342,10 @@ describe('EtherTokenWrapper', () => {
const differentEventName = EtherTokenEvents.Transfer; const differentEventName = EtherTokenEvents.Transfer;
const indexFilterValues = {}; const indexFilterValues = {};
const logs = await zeroEx.etherToken.getLogsAsync( const logs = await zeroEx.etherToken.getLogsAsync(
etherTokenAddress, differentEventName, blockRange, indexFilterValues, etherTokenAddress,
differentEventName,
blockRange,
indexFilterValues,
); );
expect(logs).to.have.length(0); expect(logs).to.have.length(0);
}); });
@ -333,7 +359,10 @@ describe('EtherTokenWrapper', () => {
_owner: addressWithETH, _owner: addressWithETH,
}; };
const logs = await zeroEx.etherToken.getLogsAsync<ApprovalContractEventArgs>( const logs = await zeroEx.etherToken.getLogsAsync<ApprovalContractEventArgs>(
etherTokenAddress, eventName, blockRange, indexFilterValues, etherTokenAddress,
eventName,
blockRange,
indexFilterValues,
); );
expect(logs).to.have.length(1); expect(logs).to.have.length(1);
const args = logs[0].args; const args = logs[0].args;

View File

@ -5,9 +5,7 @@ import 'mocha';
import * as Sinon from 'sinon'; import * as Sinon from 'sinon';
import * as Web3 from 'web3'; import * as Web3 from 'web3';
import { import { LogEvent } from '../src';
LogEvent,
} from '../src';
import { EventWatcher } from '../src/order_watcher/event_watcher'; import { EventWatcher } from '../src/order_watcher/event_watcher';
import { DoneCallback } from '../src/types'; import { DoneCallback } from '../src/types';

View File

@ -45,17 +45,31 @@ describe('ExchangeTransferSimulator', () => {
beforeEach(() => { beforeEach(() => {
exchangeTransferSimulator = new ExchangeTransferSimulator(zeroEx.token, BlockParamLiteral.Latest); exchangeTransferSimulator = new ExchangeTransferSimulator(zeroEx.token, BlockParamLiteral.Latest);
}); });
it('throws if the user doesn\'t have enough allowance', async () => { it("throws if the user doesn't have enough allowance", async () => {
return expect(exchangeTransferSimulator.transferFromAsync( return expect(
exampleTokenAddress, sender, recipient, transferAmount, TradeSide.Taker, TransferType.Trade, exchangeTransferSimulator.transferFromAsync(
)).to.be.rejectedWith(ExchangeContractErrs.InsufficientTakerAllowance); exampleTokenAddress,
sender,
recipient,
transferAmount,
TradeSide.Taker,
TransferType.Trade,
),
).to.be.rejectedWith(ExchangeContractErrs.InsufficientTakerAllowance);
}); });
it('throws if the user doesn\'t have enough balance', async () => { it("throws if the user doesn't have enough balance", async () => {
txHash = await zeroEx.token.setProxyAllowanceAsync(exampleTokenAddress, sender, transferAmount); txHash = await zeroEx.token.setProxyAllowanceAsync(exampleTokenAddress, sender, transferAmount);
await zeroEx.awaitTransactionMinedAsync(txHash); await zeroEx.awaitTransactionMinedAsync(txHash);
return expect(exchangeTransferSimulator.transferFromAsync( return expect(
exampleTokenAddress, sender, recipient, transferAmount, TradeSide.Maker, TransferType.Trade, exchangeTransferSimulator.transferFromAsync(
)).to.be.rejectedWith(ExchangeContractErrs.InsufficientMakerBalance); exampleTokenAddress,
sender,
recipient,
transferAmount,
TradeSide.Maker,
TransferType.Trade,
),
).to.be.rejectedWith(ExchangeContractErrs.InsufficientMakerBalance);
}); });
it('updates balances and proxyAllowance after transfer', async () => { it('updates balances and proxyAllowance after transfer', async () => {
txHash = await zeroEx.token.transferAsync(exampleTokenAddress, coinbase, sender, transferAmount); txHash = await zeroEx.token.transferAsync(exampleTokenAddress, coinbase, sender, transferAmount);
@ -63,7 +77,12 @@ describe('ExchangeTransferSimulator', () => {
txHash = await zeroEx.token.setProxyAllowanceAsync(exampleTokenAddress, sender, transferAmount); txHash = await zeroEx.token.setProxyAllowanceAsync(exampleTokenAddress, sender, transferAmount);
await zeroEx.awaitTransactionMinedAsync(txHash); await zeroEx.awaitTransactionMinedAsync(txHash);
await exchangeTransferSimulator.transferFromAsync( await exchangeTransferSimulator.transferFromAsync(
exampleTokenAddress, sender, recipient, transferAmount, TradeSide.Taker, TransferType.Trade, exampleTokenAddress,
sender,
recipient,
transferAmount,
TradeSide.Taker,
TransferType.Trade,
); );
const store = (exchangeTransferSimulator as any)._store; const store = (exchangeTransferSimulator as any)._store;
const senderBalance = await store.getBalanceAsync(exampleTokenAddress, sender); const senderBalance = await store.getBalanceAsync(exampleTokenAddress, sender);
@ -73,13 +92,18 @@ describe('ExchangeTransferSimulator', () => {
expect(recipientBalance).to.be.bignumber.equal(transferAmount); expect(recipientBalance).to.be.bignumber.equal(transferAmount);
expect(senderProxyAllowance).to.be.bignumber.equal(0); expect(senderProxyAllowance).to.be.bignumber.equal(0);
}); });
it('doesn\'t update proxyAllowance after transfer if unlimited', async () => { it("doesn't update proxyAllowance after transfer if unlimited", async () => {
txHash = await zeroEx.token.transferAsync(exampleTokenAddress, coinbase, sender, transferAmount); txHash = await zeroEx.token.transferAsync(exampleTokenAddress, coinbase, sender, transferAmount);
await zeroEx.awaitTransactionMinedAsync(txHash); await zeroEx.awaitTransactionMinedAsync(txHash);
txHash = await zeroEx.token.setUnlimitedProxyAllowanceAsync(exampleTokenAddress, sender); txHash = await zeroEx.token.setUnlimitedProxyAllowanceAsync(exampleTokenAddress, sender);
await zeroEx.awaitTransactionMinedAsync(txHash); await zeroEx.awaitTransactionMinedAsync(txHash);
await exchangeTransferSimulator.transferFromAsync( await exchangeTransferSimulator.transferFromAsync(
exampleTokenAddress, sender, recipient, transferAmount, TradeSide.Taker, TransferType.Trade, exampleTokenAddress,
sender,
recipient,
transferAmount,
TradeSide.Taker,
TransferType.Trade,
); );
const store = (exchangeTransferSimulator as any)._store; const store = (exchangeTransferSimulator as any)._store;
const senderBalance = await store.getBalanceAsync(exampleTokenAddress, sender); const senderBalance = await store.getBalanceAsync(exampleTokenAddress, sender);

View File

@ -80,10 +80,18 @@ describe('ExchangeWrapper', () => {
const fillableAmount = new BigNumber(5); const fillableAmount = new BigNumber(5);
const partialFillTakerAmount = new BigNumber(2); const partialFillTakerAmount = new BigNumber(2);
const signedOrder = await fillScenarios.createFillableSignedOrderAsync( const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount, makerTokenAddress,
takerTokenAddress,
makerAddress,
takerAddress,
fillableAmount,
); );
const anotherSignedOrder = await fillScenarios.createFillableSignedOrderAsync( const anotherSignedOrder = await fillScenarios.createFillableSignedOrderAsync(
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount, makerTokenAddress,
takerTokenAddress,
makerAddress,
takerAddress,
fillableAmount,
); );
const orderFillRequests = [ const orderFillRequests = [
{ {
@ -103,7 +111,11 @@ describe('ExchangeWrapper', () => {
const fillableAmount = new BigNumber(5); const fillableAmount = new BigNumber(5);
beforeEach(async () => { beforeEach(async () => {
signedOrder = await fillScenarios.createFillableSignedOrderAsync( signedOrder = await fillScenarios.createFillableSignedOrderAsync(
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount, makerTokenAddress,
takerTokenAddress,
makerAddress,
takerAddress,
fillableAmount,
); );
orderFillRequests = [ orderFillRequests = [
{ {
@ -113,18 +125,23 @@ describe('ExchangeWrapper', () => {
]; ];
}); });
it('should validate when orderTransactionOptions are not present', async () => { it('should validate when orderTransactionOptions are not present', async () => {
return expect(zeroEx.exchange.batchFillOrKillAsync(orderFillRequests, takerAddress)) return expect(
.to.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero); zeroEx.exchange.batchFillOrKillAsync(orderFillRequests, takerAddress),
).to.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero);
}); });
it('should validate when orderTransactionOptions specify to validate', async () => { it('should validate when orderTransactionOptions specify to validate', async () => {
return expect(zeroEx.exchange.batchFillOrKillAsync(orderFillRequests, takerAddress, { return expect(
zeroEx.exchange.batchFillOrKillAsync(orderFillRequests, takerAddress, {
shouldValidate: true, shouldValidate: true,
})).to.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero); }),
).to.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero);
}); });
it('should not validate when orderTransactionOptions specify not to validate', async () => { it('should not validate when orderTransactionOptions specify not to validate', async () => {
return expect(zeroEx.exchange.batchFillOrKillAsync(orderFillRequests, takerAddress, { return expect(
zeroEx.exchange.batchFillOrKillAsync(orderFillRequests, takerAddress, {
shouldValidate: false, shouldValidate: false,
})).to.not.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero); }),
).to.not.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero);
}); });
}); });
}); });
@ -133,57 +150,78 @@ describe('ExchangeWrapper', () => {
const fillableAmount = new BigNumber(5); const fillableAmount = new BigNumber(5);
beforeEach(async () => { beforeEach(async () => {
signedOrder = await fillScenarios.createFillableSignedOrderAsync( signedOrder = await fillScenarios.createFillableSignedOrderAsync(
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount, makerTokenAddress,
takerTokenAddress,
makerAddress,
takerAddress,
fillableAmount,
); );
}); });
describe('successful fills', () => { describe('successful fills', () => {
it('should fill a valid order', async () => { it('should fill a valid order', async () => {
expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, makerAddress)) expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, makerAddress)).to.be.bignumber.equal(
.to.be.bignumber.equal(fillableAmount); fillableAmount,
expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, makerAddress)) );
.to.be.bignumber.equal(0); expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, makerAddress)).to.be.bignumber.equal(
expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, takerAddress)) 0,
.to.be.bignumber.equal(0); );
expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, takerAddress)) expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, takerAddress)).to.be.bignumber.equal(
.to.be.bignumber.equal(fillableAmount); 0,
);
expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, takerAddress)).to.be.bignumber.equal(
fillableAmount,
);
await zeroEx.exchange.fillOrKillOrderAsync(signedOrder, takerTokenFillAmount, takerAddress); await zeroEx.exchange.fillOrKillOrderAsync(signedOrder, takerTokenFillAmount, takerAddress);
expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, makerAddress)) expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, makerAddress)).to.be.bignumber.equal(
.to.be.bignumber.equal(fillableAmount.minus(takerTokenFillAmount)); fillableAmount.minus(takerTokenFillAmount),
expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, makerAddress)) );
.to.be.bignumber.equal(takerTokenFillAmount); expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, makerAddress)).to.be.bignumber.equal(
expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, takerAddress)) takerTokenFillAmount,
.to.be.bignumber.equal(takerTokenFillAmount); );
expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, takerAddress)) expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, takerAddress)).to.be.bignumber.equal(
.to.be.bignumber.equal(fillableAmount.minus(takerTokenFillAmount)); takerTokenFillAmount,
);
expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, takerAddress)).to.be.bignumber.equal(
fillableAmount.minus(takerTokenFillAmount),
);
}); });
it('should partially fill a valid order', async () => { it('should partially fill a valid order', async () => {
const partialFillAmount = new BigNumber(3); const partialFillAmount = new BigNumber(3);
await zeroEx.exchange.fillOrKillOrderAsync(signedOrder, partialFillAmount, takerAddress); await zeroEx.exchange.fillOrKillOrderAsync(signedOrder, partialFillAmount, takerAddress);
expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, makerAddress)) expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, makerAddress)).to.be.bignumber.equal(
.to.be.bignumber.equal(fillableAmount.minus(partialFillAmount)); fillableAmount.minus(partialFillAmount),
expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, makerAddress)) );
.to.be.bignumber.equal(partialFillAmount); expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, makerAddress)).to.be.bignumber.equal(
expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, takerAddress)) partialFillAmount,
.to.be.bignumber.equal(partialFillAmount); );
expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, takerAddress)) expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, takerAddress)).to.be.bignumber.equal(
.to.be.bignumber.equal(fillableAmount.minus(partialFillAmount)); partialFillAmount,
);
expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, takerAddress)).to.be.bignumber.equal(
fillableAmount.minus(partialFillAmount),
);
}); });
}); });
describe('order transaction options', () => { describe('order transaction options', () => {
const emptyFillableAmount = new BigNumber(0); const emptyFillableAmount = new BigNumber(0);
it('should validate when orderTransactionOptions are not present', async () => { it('should validate when orderTransactionOptions are not present', async () => {
return expect(zeroEx.exchange.fillOrKillOrderAsync(signedOrder, emptyFillableAmount, takerAddress)) return expect(
.to.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero); zeroEx.exchange.fillOrKillOrderAsync(signedOrder, emptyFillableAmount, takerAddress),
).to.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero);
}); });
it('should validate when orderTransactionOptions specify to validate', async () => { it('should validate when orderTransactionOptions specify to validate', async () => {
return expect(zeroEx.exchange.fillOrKillOrderAsync(signedOrder, emptyFillableAmount, takerAddress, { return expect(
zeroEx.exchange.fillOrKillOrderAsync(signedOrder, emptyFillableAmount, takerAddress, {
shouldValidate: true, shouldValidate: true,
})).to.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero); }),
).to.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero);
}); });
it('should not validate when orderTransactionOptions specify not to validate', async () => { it('should not validate when orderTransactionOptions specify not to validate', async () => {
return expect(zeroEx.exchange.fillOrKillOrderAsync(signedOrder, emptyFillableAmount, takerAddress, { return expect(
zeroEx.exchange.fillOrKillOrderAsync(signedOrder, emptyFillableAmount, takerAddress, {
shouldValidate: false, shouldValidate: false,
})).to.not.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero); }),
).to.not.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero);
}); });
}); });
}); });
@ -209,57 +247,96 @@ describe('ExchangeWrapper', () => {
describe('successful fills', () => { describe('successful fills', () => {
it('should fill a valid order', async () => { it('should fill a valid order', async () => {
const signedOrder = await fillScenarios.createFillableSignedOrderAsync( const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount, makerTokenAddress,
takerTokenAddress,
makerAddress,
takerAddress,
fillableAmount,
);
expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, makerAddress)).to.be.bignumber.equal(
fillableAmount,
);
expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, makerAddress)).to.be.bignumber.equal(
0,
);
expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, takerAddress)).to.be.bignumber.equal(
0,
);
expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, takerAddress)).to.be.bignumber.equal(
fillableAmount,
); );
expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, makerAddress))
.to.be.bignumber.equal(fillableAmount);
expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, makerAddress))
.to.be.bignumber.equal(0);
expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, takerAddress))
.to.be.bignumber.equal(0);
expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, takerAddress))
.to.be.bignumber.equal(fillableAmount);
const txHash = await zeroEx.exchange.fillOrderAsync( const txHash = await zeroEx.exchange.fillOrderAsync(
signedOrder, takerTokenFillAmount, shouldThrowOnInsufficientBalanceOrAllowance, takerAddress); signedOrder,
takerTokenFillAmount,
shouldThrowOnInsufficientBalanceOrAllowance,
takerAddress,
);
await zeroEx.awaitTransactionMinedAsync(txHash); await zeroEx.awaitTransactionMinedAsync(txHash);
expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, makerAddress)) expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, makerAddress)).to.be.bignumber.equal(
.to.be.bignumber.equal(fillableAmount.minus(takerTokenFillAmount)); fillableAmount.minus(takerTokenFillAmount),
expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, makerAddress)) );
.to.be.bignumber.equal(takerTokenFillAmount); expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, makerAddress)).to.be.bignumber.equal(
expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, takerAddress)) takerTokenFillAmount,
.to.be.bignumber.equal(takerTokenFillAmount); );
expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, takerAddress)) expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, takerAddress)).to.be.bignumber.equal(
.to.be.bignumber.equal(fillableAmount.minus(takerTokenFillAmount)); takerTokenFillAmount,
);
expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, takerAddress)).to.be.bignumber.equal(
fillableAmount.minus(takerTokenFillAmount),
);
}); });
it('should partially fill the valid order', async () => { it('should partially fill the valid order', async () => {
const signedOrder = await fillScenarios.createFillableSignedOrderAsync( const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount, makerTokenAddress,
takerTokenAddress,
makerAddress,
takerAddress,
fillableAmount,
); );
const partialFillAmount = new BigNumber(3); const partialFillAmount = new BigNumber(3);
const txHash = await zeroEx.exchange.fillOrderAsync( const txHash = await zeroEx.exchange.fillOrderAsync(
signedOrder, partialFillAmount, shouldThrowOnInsufficientBalanceOrAllowance, takerAddress); signedOrder,
partialFillAmount,
shouldThrowOnInsufficientBalanceOrAllowance,
takerAddress,
);
await zeroEx.awaitTransactionMinedAsync(txHash); await zeroEx.awaitTransactionMinedAsync(txHash);
expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, makerAddress)) expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, makerAddress)).to.be.bignumber.equal(
.to.be.bignumber.equal(fillableAmount.minus(partialFillAmount)); fillableAmount.minus(partialFillAmount),
expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, makerAddress)) );
.to.be.bignumber.equal(partialFillAmount); expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, makerAddress)).to.be.bignumber.equal(
expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, takerAddress)) partialFillAmount,
.to.be.bignumber.equal(partialFillAmount); );
expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, takerAddress)) expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, takerAddress)).to.be.bignumber.equal(
.to.be.bignumber.equal(fillableAmount.minus(partialFillAmount)); partialFillAmount,
);
expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, takerAddress)).to.be.bignumber.equal(
fillableAmount.minus(partialFillAmount),
);
}); });
it('should fill the valid orders with fees', async () => { it('should fill the valid orders with fees', async () => {
const makerFee = new BigNumber(1); const makerFee = new BigNumber(1);
const takerFee = new BigNumber(2); const takerFee = new BigNumber(2);
const signedOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync( const signedOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync(
makerTokenAddress, takerTokenAddress, makerFee, takerFee, makerTokenAddress,
makerAddress, takerAddress, fillableAmount, feeRecipient, takerTokenAddress,
makerFee,
takerFee,
makerAddress,
takerAddress,
fillableAmount,
feeRecipient,
); );
const txHash = await zeroEx.exchange.fillOrderAsync( const txHash = await zeroEx.exchange.fillOrderAsync(
signedOrder, takerTokenFillAmount, shouldThrowOnInsufficientBalanceOrAllowance, takerAddress); signedOrder,
takerTokenFillAmount,
shouldThrowOnInsufficientBalanceOrAllowance,
takerAddress,
);
await zeroEx.awaitTransactionMinedAsync(txHash); await zeroEx.awaitTransactionMinedAsync(txHash);
expect(await zeroEx.token.getBalanceAsync(zrxTokenAddress, feeRecipient)) expect(await zeroEx.token.getBalanceAsync(zrxTokenAddress, feeRecipient)).to.be.bignumber.equal(
.to.be.bignumber.equal(makerFee.plus(takerFee)); makerFee.plus(takerFee),
);
}); });
}); });
describe('order transaction options', () => { describe('order transaction options', () => {
@ -267,25 +344,48 @@ describe('ExchangeWrapper', () => {
const emptyFillTakerAmount = new BigNumber(0); const emptyFillTakerAmount = new BigNumber(0);
beforeEach(async () => { beforeEach(async () => {
signedOrder = await fillScenarios.createFillableSignedOrderAsync( signedOrder = await fillScenarios.createFillableSignedOrderAsync(
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount, makerTokenAddress,
takerTokenAddress,
makerAddress,
takerAddress,
fillableAmount,
); );
}); });
it('should validate when orderTransactionOptions are not present', async () => { it('should validate when orderTransactionOptions are not present', async () => {
return expect(zeroEx.exchange.fillOrderAsync( return expect(
signedOrder, emptyFillTakerAmount, shouldThrowOnInsufficientBalanceOrAllowance, takerAddress, zeroEx.exchange.fillOrderAsync(
)).to.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero); signedOrder,
emptyFillTakerAmount,
shouldThrowOnInsufficientBalanceOrAllowance,
takerAddress,
),
).to.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero);
}); });
it('should validate when orderTransactionOptions specify to validate', async () => { it('should validate when orderTransactionOptions specify to validate', async () => {
return expect(zeroEx.exchange.fillOrderAsync( return expect(
signedOrder, emptyFillTakerAmount, shouldThrowOnInsufficientBalanceOrAllowance, takerAddress, { zeroEx.exchange.fillOrderAsync(
signedOrder,
emptyFillTakerAmount,
shouldThrowOnInsufficientBalanceOrAllowance,
takerAddress,
{
shouldValidate: true, shouldValidate: true,
})).to.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero); },
),
).to.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero);
}); });
it('should not validate when orderTransactionOptions specify not to validate', async () => { it('should not validate when orderTransactionOptions specify not to validate', async () => {
return expect(zeroEx.exchange.fillOrderAsync( return expect(
signedOrder, emptyFillTakerAmount, shouldThrowOnInsufficientBalanceOrAllowance, takerAddress, { zeroEx.exchange.fillOrderAsync(
signedOrder,
emptyFillTakerAmount,
shouldThrowOnInsufficientBalanceOrAllowance,
takerAddress,
{
shouldValidate: false, shouldValidate: false,
})).to.not.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero); },
),
).to.not.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero);
}); });
}); });
}); });
@ -297,11 +397,19 @@ describe('ExchangeWrapper', () => {
let orderFillBatch: OrderFillRequest[]; let orderFillBatch: OrderFillRequest[];
beforeEach(async () => { beforeEach(async () => {
signedOrder = await fillScenarios.createFillableSignedOrderAsync( signedOrder = await fillScenarios.createFillableSignedOrderAsync(
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount, makerTokenAddress,
takerTokenAddress,
makerAddress,
takerAddress,
fillableAmount,
); );
signedOrderHashHex = ZeroEx.getOrderHashHex(signedOrder); signedOrderHashHex = ZeroEx.getOrderHashHex(signedOrder);
anotherSignedOrder = await fillScenarios.createFillableSignedOrderAsync( anotherSignedOrder = await fillScenarios.createFillableSignedOrderAsync(
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount, makerTokenAddress,
takerTokenAddress,
makerAddress,
takerAddress,
fillableAmount,
); );
anotherOrderHashHex = ZeroEx.getOrderHashHex(anotherSignedOrder); anotherOrderHashHex = ZeroEx.getOrderHashHex(anotherSignedOrder);
}); });
@ -319,13 +427,20 @@ describe('ExchangeWrapper', () => {
]; ];
}); });
it('should throw if a batch is empty', async () => { it('should throw if a batch is empty', async () => {
return expect(zeroEx.exchange.batchFillOrdersAsync( return expect(
[], shouldThrowOnInsufficientBalanceOrAllowance, takerAddress), zeroEx.exchange.batchFillOrdersAsync(
[],
shouldThrowOnInsufficientBalanceOrAllowance,
takerAddress,
),
).to.be.rejectedWith(ExchangeContractErrs.BatchOrdersMustHaveAtLeastOneItem); ).to.be.rejectedWith(ExchangeContractErrs.BatchOrdersMustHaveAtLeastOneItem);
}); });
it('should successfully fill multiple orders', async () => { it('should successfully fill multiple orders', async () => {
const txHash = await zeroEx.exchange.batchFillOrdersAsync( const txHash = await zeroEx.exchange.batchFillOrdersAsync(
orderFillBatch, shouldThrowOnInsufficientBalanceOrAllowance, takerAddress); orderFillBatch,
shouldThrowOnInsufficientBalanceOrAllowance,
takerAddress,
);
await zeroEx.awaitTransactionMinedAsync(txHash); await zeroEx.awaitTransactionMinedAsync(txHash);
const filledAmount = await zeroEx.exchange.getFilledTakerAmountAsync(signedOrderHashHex); const filledAmount = await zeroEx.exchange.getFilledTakerAmountAsync(signedOrderHashHex);
const anotherFilledAmount = await zeroEx.exchange.getFilledTakerAmountAsync(anotherOrderHashHex); const anotherFilledAmount = await zeroEx.exchange.getFilledTakerAmountAsync(anotherOrderHashHex);
@ -348,21 +463,37 @@ describe('ExchangeWrapper', () => {
]; ];
}); });
it('should validate when orderTransactionOptions are not present', async () => { it('should validate when orderTransactionOptions are not present', async () => {
return expect(zeroEx.exchange.batchFillOrdersAsync( return expect(
orderFillBatch, shouldThrowOnInsufficientBalanceOrAllowance, takerAddress), zeroEx.exchange.batchFillOrdersAsync(
orderFillBatch,
shouldThrowOnInsufficientBalanceOrAllowance,
takerAddress,
),
).to.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero); ).to.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero);
}); });
it('should validate when orderTransactionOptions specify to validate', async () => { it('should validate when orderTransactionOptions specify to validate', async () => {
return expect(zeroEx.exchange.batchFillOrdersAsync( return expect(
orderFillBatch, shouldThrowOnInsufficientBalanceOrAllowance, takerAddress, { zeroEx.exchange.batchFillOrdersAsync(
orderFillBatch,
shouldThrowOnInsufficientBalanceOrAllowance,
takerAddress,
{
shouldValidate: true, shouldValidate: true,
})).to.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero); },
),
).to.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero);
}); });
it('should not validate when orderTransactionOptions specify not to validate', async () => { it('should not validate when orderTransactionOptions specify not to validate', async () => {
return expect(zeroEx.exchange.batchFillOrdersAsync( return expect(
orderFillBatch, shouldThrowOnInsufficientBalanceOrAllowance, takerAddress, { zeroEx.exchange.batchFillOrdersAsync(
orderFillBatch,
shouldThrowOnInsufficientBalanceOrAllowance,
takerAddress,
{
shouldValidate: false, shouldValidate: false,
})).to.not.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero); },
),
).to.not.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero);
}); });
}); });
}); });
@ -375,24 +506,40 @@ describe('ExchangeWrapper', () => {
const fillUpToAmount = fillableAmount.plus(fillableAmount).minus(1); const fillUpToAmount = fillableAmount.plus(fillableAmount).minus(1);
beforeEach(async () => { beforeEach(async () => {
signedOrder = await fillScenarios.createFillableSignedOrderAsync( signedOrder = await fillScenarios.createFillableSignedOrderAsync(
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount, makerTokenAddress,
takerTokenAddress,
makerAddress,
takerAddress,
fillableAmount,
); );
signedOrderHashHex = ZeroEx.getOrderHashHex(signedOrder); signedOrderHashHex = ZeroEx.getOrderHashHex(signedOrder);
anotherSignedOrder = await fillScenarios.createFillableSignedOrderAsync( anotherSignedOrder = await fillScenarios.createFillableSignedOrderAsync(
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount, makerTokenAddress,
takerTokenAddress,
makerAddress,
takerAddress,
fillableAmount,
); );
anotherOrderHashHex = ZeroEx.getOrderHashHex(anotherSignedOrder); anotherOrderHashHex = ZeroEx.getOrderHashHex(anotherSignedOrder);
signedOrders = [signedOrder, anotherSignedOrder]; signedOrders = [signedOrder, anotherSignedOrder];
}); });
describe('successful batch fills', () => { describe('successful batch fills', () => {
it('should throw if a batch is empty', async () => { it('should throw if a batch is empty', async () => {
return expect(zeroEx.exchange.fillOrdersUpToAsync( return expect(
[], fillUpToAmount, shouldThrowOnInsufficientBalanceOrAllowance, takerAddress), zeroEx.exchange.fillOrdersUpToAsync(
[],
fillUpToAmount,
shouldThrowOnInsufficientBalanceOrAllowance,
takerAddress,
),
).to.be.rejectedWith(ExchangeContractErrs.BatchOrdersMustHaveAtLeastOneItem); ).to.be.rejectedWith(ExchangeContractErrs.BatchOrdersMustHaveAtLeastOneItem);
}); });
it('should successfully fill up to specified amount', async () => { it('should successfully fill up to specified amount', async () => {
const txHash = await zeroEx.exchange.fillOrdersUpToAsync( const txHash = await zeroEx.exchange.fillOrdersUpToAsync(
signedOrders, fillUpToAmount, shouldThrowOnInsufficientBalanceOrAllowance, takerAddress, signedOrders,
fillUpToAmount,
shouldThrowOnInsufficientBalanceOrAllowance,
takerAddress,
); );
await zeroEx.awaitTransactionMinedAsync(txHash); await zeroEx.awaitTransactionMinedAsync(txHash);
const filledAmount = await zeroEx.exchange.getFilledTakerAmountAsync(signedOrderHashHex); const filledAmount = await zeroEx.exchange.getFilledTakerAmountAsync(signedOrderHashHex);
@ -405,21 +552,40 @@ describe('ExchangeWrapper', () => {
describe('order transaction options', () => { describe('order transaction options', () => {
const emptyFillUpToAmount = new BigNumber(0); const emptyFillUpToAmount = new BigNumber(0);
it('should validate when orderTransactionOptions are not present', async () => { it('should validate when orderTransactionOptions are not present', async () => {
return expect(zeroEx.exchange.fillOrdersUpToAsync( return expect(
signedOrders, emptyFillUpToAmount, shouldThrowOnInsufficientBalanceOrAllowance, takerAddress, zeroEx.exchange.fillOrdersUpToAsync(
)).to.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero); signedOrders,
emptyFillUpToAmount,
shouldThrowOnInsufficientBalanceOrAllowance,
takerAddress,
),
).to.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero);
}); });
it('should validate when orderTransactionOptions specify to validate', async () => { it('should validate when orderTransactionOptions specify to validate', async () => {
return expect(zeroEx.exchange.fillOrdersUpToAsync( return expect(
signedOrders, emptyFillUpToAmount, shouldThrowOnInsufficientBalanceOrAllowance, takerAddress, { zeroEx.exchange.fillOrdersUpToAsync(
signedOrders,
emptyFillUpToAmount,
shouldThrowOnInsufficientBalanceOrAllowance,
takerAddress,
{
shouldValidate: true, shouldValidate: true,
})).to.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero); },
),
).to.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero);
}); });
it('should not validate when orderTransactionOptions specify not to validate', async () => { it('should not validate when orderTransactionOptions specify not to validate', async () => {
return expect(zeroEx.exchange.fillOrdersUpToAsync( return expect(
signedOrders, emptyFillUpToAmount, shouldThrowOnInsufficientBalanceOrAllowance, takerAddress, { zeroEx.exchange.fillOrdersUpToAsync(
signedOrders,
emptyFillUpToAmount,
shouldThrowOnInsufficientBalanceOrAllowance,
takerAddress,
{
shouldValidate: false, shouldValidate: false,
})).to.not.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero); },
),
).to.not.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero);
}); });
}); });
}); });
@ -440,7 +606,11 @@ describe('ExchangeWrapper', () => {
makerTokenAddress = makerToken.address; makerTokenAddress = makerToken.address;
takerTokenAddress = takerToken.address; takerTokenAddress = takerToken.address;
signedOrder = await fillScenarios.createFillableSignedOrderAsync( signedOrder = await fillScenarios.createFillableSignedOrderAsync(
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount, makerTokenAddress,
takerTokenAddress,
makerAddress,
takerAddress,
fillableAmount,
); );
orderHashHex = ZeroEx.getOrderHashHex(signedOrder); orderHashHex = ZeroEx.getOrderHashHex(signedOrder);
}); });
@ -456,18 +626,23 @@ describe('ExchangeWrapper', () => {
describe('order transaction options', () => { describe('order transaction options', () => {
const emptyCancelTakerTokenAmount = new BigNumber(0); const emptyCancelTakerTokenAmount = new BigNumber(0);
it('should validate when orderTransactionOptions are not present', async () => { it('should validate when orderTransactionOptions are not present', async () => {
return expect(zeroEx.exchange.cancelOrderAsync(signedOrder, emptyCancelTakerTokenAmount)) return expect(
.to.be.rejectedWith(ExchangeContractErrs.OrderCancelAmountZero); zeroEx.exchange.cancelOrderAsync(signedOrder, emptyCancelTakerTokenAmount),
).to.be.rejectedWith(ExchangeContractErrs.OrderCancelAmountZero);
}); });
it('should validate when orderTransactionOptions specify to validate', async () => { it('should validate when orderTransactionOptions specify to validate', async () => {
return expect(zeroEx.exchange.cancelOrderAsync(signedOrder, emptyCancelTakerTokenAmount, { return expect(
zeroEx.exchange.cancelOrderAsync(signedOrder, emptyCancelTakerTokenAmount, {
shouldValidate: true, shouldValidate: true,
})).to.be.rejectedWith(ExchangeContractErrs.OrderCancelAmountZero); }),
).to.be.rejectedWith(ExchangeContractErrs.OrderCancelAmountZero);
}); });
it('should not validate when orderTransactionOptions specify not to validate', async () => { it('should not validate when orderTransactionOptions specify not to validate', async () => {
return expect(zeroEx.exchange.cancelOrderAsync(signedOrder, emptyCancelTakerTokenAmount, { return expect(
zeroEx.exchange.cancelOrderAsync(signedOrder, emptyCancelTakerTokenAmount, {
shouldValidate: false, shouldValidate: false,
})).to.not.be.rejectedWith(ExchangeContractErrs.OrderCancelAmountZero); }),
).to.not.be.rejectedWith(ExchangeContractErrs.OrderCancelAmountZero);
}); });
}); });
}); });
@ -477,7 +652,11 @@ describe('ExchangeWrapper', () => {
let cancelBatch: OrderCancellationRequest[]; let cancelBatch: OrderCancellationRequest[];
beforeEach(async () => { beforeEach(async () => {
anotherSignedOrder = await fillScenarios.createFillableSignedOrderAsync( anotherSignedOrder = await fillScenarios.createFillableSignedOrderAsync(
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount, makerTokenAddress,
takerTokenAddress,
makerAddress,
takerAddress,
fillableAmount,
); );
anotherOrderHashHex = ZeroEx.getOrderHashHex(anotherSignedOrder); anotherOrderHashHex = ZeroEx.getOrderHashHex(anotherSignedOrder);
cancelBatch = [ cancelBatch = [
@ -494,15 +673,21 @@ describe('ExchangeWrapper', () => {
describe('failed batch cancels', () => { describe('failed batch cancels', () => {
it('should throw when orders have different makers', async () => { it('should throw when orders have different makers', async () => {
const signedOrderWithDifferentMaker = await fillScenarios.createFillableSignedOrderAsync( const signedOrderWithDifferentMaker = await fillScenarios.createFillableSignedOrderAsync(
makerTokenAddress, takerTokenAddress, takerAddress, takerAddress, fillableAmount, makerTokenAddress,
takerTokenAddress,
takerAddress,
takerAddress,
fillableAmount,
); );
return expect(zeroEx.exchange.batchCancelOrdersAsync([ return expect(
zeroEx.exchange.batchCancelOrdersAsync([
cancelBatch[0], cancelBatch[0],
{ {
order: signedOrderWithDifferentMaker, order: signedOrderWithDifferentMaker,
takerTokenCancelAmount: cancelAmount, takerTokenCancelAmount: cancelAmount,
}, },
])).to.be.rejectedWith(ExchangeContractErrs.MultipleMakersInSingleCancelBatchDisallowed); ]),
).to.be.rejectedWith(ExchangeContractErrs.MultipleMakersInSingleCancelBatchDisallowed);
}); });
}); });
describe('successful batch cancels', () => { describe('successful batch cancels', () => {
@ -531,18 +716,23 @@ describe('ExchangeWrapper', () => {
]; ];
}); });
it('should validate when orderTransactionOptions are not present', async () => { it('should validate when orderTransactionOptions are not present', async () => {
return expect(zeroEx.exchange.batchCancelOrdersAsync(cancelBatch)) return expect(zeroEx.exchange.batchCancelOrdersAsync(cancelBatch)).to.be.rejectedWith(
.to.be.rejectedWith(ExchangeContractErrs.OrderCancelAmountZero); ExchangeContractErrs.OrderCancelAmountZero,
);
}); });
it('should validate when orderTransactionOptions specify to validate', async () => { it('should validate when orderTransactionOptions specify to validate', async () => {
return expect(zeroEx.exchange.batchCancelOrdersAsync(cancelBatch, { return expect(
zeroEx.exchange.batchCancelOrdersAsync(cancelBatch, {
shouldValidate: true, shouldValidate: true,
})).to.be.rejectedWith(ExchangeContractErrs.OrderCancelAmountZero); }),
).to.be.rejectedWith(ExchangeContractErrs.OrderCancelAmountZero);
}); });
it('should not validate when orderTransactionOptions specify not to validate', async () => { it('should not validate when orderTransactionOptions specify not to validate', async () => {
return expect(zeroEx.exchange.batchCancelOrdersAsync(cancelBatch, { return expect(
zeroEx.exchange.batchCancelOrdersAsync(cancelBatch, {
shouldValidate: false, shouldValidate: false,
})).to.not.be.rejectedWith(ExchangeContractErrs.OrderCancelAmountZero); }),
).to.not.be.rejectedWith(ExchangeContractErrs.OrderCancelAmountZero);
}); });
}); });
}); });
@ -566,7 +756,11 @@ describe('ExchangeWrapper', () => {
fillableAmount = new BigNumber(5); fillableAmount = new BigNumber(5);
partialFillAmount = new BigNumber(2); partialFillAmount = new BigNumber(2);
signedOrder = await fillScenarios.createPartiallyFilledSignedOrderAsync( signedOrder = await fillScenarios.createPartiallyFilledSignedOrderAsync(
makerTokenAddress, takerTokenAddress, takerAddress, fillableAmount, partialFillAmount, makerTokenAddress,
takerTokenAddress,
takerAddress,
fillableAmount,
partialFillAmount,
); );
orderHash = ZeroEx.getOrderHashHex(signedOrder); orderHash = ZeroEx.getOrderHashHex(signedOrder);
}); });
@ -590,8 +784,7 @@ describe('ExchangeWrapper', () => {
return expect(zeroEx.exchange.getFilledTakerAmountAsync(invalidOrderHashHex)).to.be.rejected(); return expect(zeroEx.exchange.getFilledTakerAmountAsync(invalidOrderHashHex)).to.be.rejected();
}); });
it('should return zero if passed a valid but non-existent orderHash', async () => { it('should return zero if passed a valid but non-existent orderHash', async () => {
const filledValueT = await zeroEx.exchange.getFilledTakerAmountAsync(NON_EXISTENT_ORDER_HASH, const filledValueT = await zeroEx.exchange.getFilledTakerAmountAsync(NON_EXISTENT_ORDER_HASH);
);
expect(filledValueT).to.be.bignumber.equal(0); expect(filledValueT).to.be.bignumber.equal(0);
}); });
it('should return the filledValueT for a valid and partially filled orderHash', async () => { it('should return the filledValueT for a valid and partially filled orderHash', async () => {
@ -641,7 +834,11 @@ describe('ExchangeWrapper', () => {
beforeEach(async () => { beforeEach(async () => {
fillableAmount = new BigNumber(5); fillableAmount = new BigNumber(5);
signedOrder = await fillScenarios.createFillableSignedOrderAsync( signedOrder = await fillScenarios.createFillableSignedOrderAsync(
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount, makerTokenAddress,
takerTokenAddress,
makerAddress,
takerAddress,
fillableAmount,
); );
}); });
afterEach(async () => { afterEach(async () => {
@ -654,42 +851,35 @@ describe('ExchangeWrapper', () => {
// Source: https://github.com/mochajs/mocha/issues/2407 // Source: https://github.com/mochajs/mocha/issues/2407
it('Should receive the LogFill event when an order is filled', (done: DoneCallback) => { it('Should receive the LogFill event when an order is filled', (done: DoneCallback) => {
(async () => { (async () => {
const callback = (err: Error, logEvent: DecodedLogEvent<LogFillContractEventArgs>) => { const callback = (err: Error, logEvent: DecodedLogEvent<LogFillContractEventArgs>) => {
expect(logEvent.log.event).to.be.equal(ExchangeEvents.LogFill); expect(logEvent.log.event).to.be.equal(ExchangeEvents.LogFill);
done(); done();
}; };
zeroEx.exchange.subscribe( zeroEx.exchange.subscribe(ExchangeEvents.LogFill, indexFilterValues, callback);
ExchangeEvents.LogFill, indexFilterValues, callback,
);
await zeroEx.exchange.fillOrderAsync( await zeroEx.exchange.fillOrderAsync(
signedOrder, takerTokenFillAmountInBaseUnits, shouldThrowOnInsufficientBalanceOrAllowance, signedOrder,
takerTokenFillAmountInBaseUnits,
shouldThrowOnInsufficientBalanceOrAllowance,
takerAddress, takerAddress,
); );
})().catch(done); })().catch(done);
}); });
it('Should receive the LogCancel event when an order is cancelled', (done: DoneCallback) => { it('Should receive the LogCancel event when an order is cancelled', (done: DoneCallback) => {
(async () => { (async () => {
const callback = (err: Error, logEvent: DecodedLogEvent<LogCancelContractEventArgs>) => { const callback = (err: Error, logEvent: DecodedLogEvent<LogCancelContractEventArgs>) => {
expect(logEvent.log.event).to.be.equal(ExchangeEvents.LogCancel); expect(logEvent.log.event).to.be.equal(ExchangeEvents.LogCancel);
done(); done();
}; };
zeroEx.exchange.subscribe( zeroEx.exchange.subscribe(ExchangeEvents.LogCancel, indexFilterValues, callback);
ExchangeEvents.LogCancel, indexFilterValues, callback,
);
await zeroEx.exchange.cancelOrderAsync(signedOrder, cancelTakerAmountInBaseUnits); await zeroEx.exchange.cancelOrderAsync(signedOrder, cancelTakerAmountInBaseUnits);
})().catch(done); })().catch(done);
}); });
it('Outstanding subscriptions are cancelled when zeroEx.setProvider called', (done: DoneCallback) => { it('Outstanding subscriptions are cancelled when zeroEx.setProvider called', (done: DoneCallback) => {
(async () => { (async () => {
const callbackNeverToBeCalled = (err: Error, logEvent: DecodedLogEvent<LogFillContractEventArgs>) => { const callbackNeverToBeCalled = (err: Error, logEvent: DecodedLogEvent<LogFillContractEventArgs>) => {
done(new Error('Expected this subscription to have been cancelled')); done(new Error('Expected this subscription to have been cancelled'));
}; };
zeroEx.exchange.subscribe( zeroEx.exchange.subscribe(ExchangeEvents.LogFill, indexFilterValues, callbackNeverToBeCalled);
ExchangeEvents.LogFill, indexFilterValues, callbackNeverToBeCalled,
);
const newProvider = web3Factory.getRpcProvider(); const newProvider = web3Factory.getRpcProvider();
zeroEx.setProvider(newProvider, constants.TESTRPC_NETWORK_ID); zeroEx.setProvider(newProvider, constants.TESTRPC_NETWORK_ID);
@ -698,11 +888,11 @@ describe('ExchangeWrapper', () => {
expect(logEvent.log.event).to.be.equal(ExchangeEvents.LogFill); expect(logEvent.log.event).to.be.equal(ExchangeEvents.LogFill);
done(); done();
}; };
zeroEx.exchange.subscribe( zeroEx.exchange.subscribe(ExchangeEvents.LogFill, indexFilterValues, callback);
ExchangeEvents.LogFill, indexFilterValues, callback,
);
await zeroEx.exchange.fillOrderAsync( await zeroEx.exchange.fillOrderAsync(
signedOrder, takerTokenFillAmountInBaseUnits, shouldThrowOnInsufficientBalanceOrAllowance, signedOrder,
takerTokenFillAmountInBaseUnits,
shouldThrowOnInsufficientBalanceOrAllowance,
takerAddress, takerAddress,
); );
})().catch(done); })().catch(done);
@ -713,11 +903,15 @@ describe('ExchangeWrapper', () => {
done(new Error('Expected this subscription to have been cancelled')); done(new Error('Expected this subscription to have been cancelled'));
}; };
const subscriptionToken = zeroEx.exchange.subscribe( const subscriptionToken = zeroEx.exchange.subscribe(
ExchangeEvents.LogFill, indexFilterValues, callbackNeverToBeCalled, ExchangeEvents.LogFill,
indexFilterValues,
callbackNeverToBeCalled,
); );
zeroEx.exchange.unsubscribe(subscriptionToken); zeroEx.exchange.unsubscribe(subscriptionToken);
await zeroEx.exchange.fillOrderAsync( await zeroEx.exchange.fillOrderAsync(
signedOrder, takerTokenFillAmountInBaseUnits, shouldThrowOnInsufficientBalanceOrAllowance, signedOrder,
takerTokenFillAmountInBaseUnits,
shouldThrowOnInsufficientBalanceOrAllowance,
takerAddress, takerAddress,
); );
done(); done();
@ -736,13 +930,18 @@ describe('ExchangeWrapper', () => {
makerTokenAddress = makerToken.address; makerTokenAddress = makerToken.address;
takerTokenAddress = takerToken.address; takerTokenAddress = takerToken.address;
}); });
it('get\'s the same hash as the local function', async () => { it("get's the same hash as the local function", async () => {
const signedOrder = await fillScenarios.createFillableSignedOrderAsync( const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount, makerTokenAddress,
takerTokenAddress,
makerAddress,
takerAddress,
fillableAmount,
); );
const orderHash = ZeroEx.getOrderHashHex(signedOrder); const orderHash = ZeroEx.getOrderHashHex(signedOrder);
const orderHashFromContract = await (zeroEx.exchange as any) const orderHashFromContract = await (zeroEx.exchange as any)._getOrderHashHexUsingContractCallAsync(
._getOrderHashHexUsingContractCallAsync(signedOrder); signedOrder,
);
expect(orderHash).to.equal(orderHashFromContract); expect(orderHash).to.equal(orderHashFromContract);
}); });
}); });
@ -773,10 +972,17 @@ describe('ExchangeWrapper', () => {
}); });
it('should get logs with decoded args emitted by LogFill', async () => { it('should get logs with decoded args emitted by LogFill', async () => {
const signedOrder = await fillScenarios.createFillableSignedOrderAsync( const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount, makerTokenAddress,
takerTokenAddress,
makerAddress,
takerAddress,
fillableAmount,
); );
txHash = await zeroEx.exchange.fillOrderAsync( txHash = await zeroEx.exchange.fillOrderAsync(
signedOrder, fillableAmount, shouldThrowOnInsufficientBalanceOrAllowance, takerAddress, signedOrder,
fillableAmount,
shouldThrowOnInsufficientBalanceOrAllowance,
takerAddress,
); );
await zeroEx.awaitTransactionMinedAsync(txHash); await zeroEx.awaitTransactionMinedAsync(txHash);
const eventName = ExchangeEvents.LogFill; const eventName = ExchangeEvents.LogFill;
@ -787,10 +993,17 @@ describe('ExchangeWrapper', () => {
}); });
it('should only get the logs with the correct event name', async () => { it('should only get the logs with the correct event name', async () => {
const signedOrder = await fillScenarios.createFillableSignedOrderAsync( const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount, makerTokenAddress,
takerTokenAddress,
makerAddress,
takerAddress,
fillableAmount,
); );
txHash = await zeroEx.exchange.fillOrderAsync( txHash = await zeroEx.exchange.fillOrderAsync(
signedOrder, fillableAmount, shouldThrowOnInsufficientBalanceOrAllowance, takerAddress, signedOrder,
fillableAmount,
shouldThrowOnInsufficientBalanceOrAllowance,
takerAddress,
); );
await zeroEx.awaitTransactionMinedAsync(txHash); await zeroEx.awaitTransactionMinedAsync(txHash);
const differentEventName = ExchangeEvents.LogCancel; const differentEventName = ExchangeEvents.LogCancel;
@ -800,19 +1013,33 @@ describe('ExchangeWrapper', () => {
}); });
it('should only get the logs with the correct indexed fields', async () => { it('should only get the logs with the correct indexed fields', async () => {
const signedOrder = await fillScenarios.createFillableSignedOrderAsync( const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount, makerTokenAddress,
takerTokenAddress,
makerAddress,
takerAddress,
fillableAmount,
); );
txHash = await zeroEx.exchange.fillOrderAsync( txHash = await zeroEx.exchange.fillOrderAsync(
signedOrder, fillableAmount, shouldThrowOnInsufficientBalanceOrAllowance, takerAddress, signedOrder,
fillableAmount,
shouldThrowOnInsufficientBalanceOrAllowance,
takerAddress,
); );
await zeroEx.awaitTransactionMinedAsync(txHash); await zeroEx.awaitTransactionMinedAsync(txHash);
const differentMakerAddress = userAddresses[2]; const differentMakerAddress = userAddresses[2];
const anotherSignedOrder = await fillScenarios.createFillableSignedOrderAsync( const anotherSignedOrder = await fillScenarios.createFillableSignedOrderAsync(
makerTokenAddress, takerTokenAddress, differentMakerAddress, takerAddress, fillableAmount, makerTokenAddress,
takerTokenAddress,
differentMakerAddress,
takerAddress,
fillableAmount,
); );
txHash = await zeroEx.exchange.fillOrderAsync( txHash = await zeroEx.exchange.fillOrderAsync(
anotherSignedOrder, fillableAmount, shouldThrowOnInsufficientBalanceOrAllowance, takerAddress, anotherSignedOrder,
fillableAmount,
shouldThrowOnInsufficientBalanceOrAllowance,
takerAddress,
); );
await zeroEx.awaitTransactionMinedAsync(txHash); await zeroEx.awaitTransactionMinedAsync(txHash);
@ -821,7 +1048,9 @@ describe('ExchangeWrapper', () => {
maker: differentMakerAddress, maker: differentMakerAddress,
}; };
const logs = await zeroEx.exchange.getLogsAsync<LogFillContractEventArgs>( const logs = await zeroEx.exchange.getLogsAsync<LogFillContractEventArgs>(
eventName, blockRange, indexFilterValues, eventName,
blockRange,
indexFilterValues,
); );
expect(logs).to.have.length(1); expect(logs).to.have.length(1);
const args = logs[0].args; const args = logs[0].args;

View File

@ -78,7 +78,11 @@ describe('ExpirationWatcher', () => {
const orderLifetimeSec = 60; const orderLifetimeSec = 60;
const expirationUnixTimestampSec = currentUnixTimestampSec.plus(orderLifetimeSec); const expirationUnixTimestampSec = currentUnixTimestampSec.plus(orderLifetimeSec);
const signedOrder = await fillScenarios.createFillableSignedOrderAsync( const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount, makerTokenAddress,
takerTokenAddress,
makerAddress,
takerAddress,
fillableAmount,
expirationUnixTimestampSec, expirationUnixTimestampSec,
); );
const orderHash = ZeroEx.getOrderHashHex(signedOrder); const orderHash = ZeroEx.getOrderHashHex(signedOrder);
@ -92,12 +96,16 @@ describe('ExpirationWatcher', () => {
timer.tick(orderLifetimeSec * 1000); timer.tick(orderLifetimeSec * 1000);
})().catch(done); })().catch(done);
}); });
it('doesn\'t emit events before order expires', (done: DoneCallback) => { it("doesn't emit events before order expires", (done: DoneCallback) => {
(async () => { (async () => {
const orderLifetimeSec = 60; const orderLifetimeSec = 60;
const expirationUnixTimestampSec = currentUnixTimestampSec.plus(orderLifetimeSec); const expirationUnixTimestampSec = currentUnixTimestampSec.plus(orderLifetimeSec);
const signedOrder = await fillScenarios.createFillableSignedOrderAsync( const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount, makerTokenAddress,
takerTokenAddress,
makerAddress,
takerAddress,
fillableAmount,
expirationUnixTimestampSec, expirationUnixTimestampSec,
); );
const orderHash = ZeroEx.getOrderHashHex(signedOrder); const orderHash = ZeroEx.getOrderHashHex(signedOrder);
@ -118,11 +126,19 @@ describe('ExpirationWatcher', () => {
const order1ExpirationUnixTimestampSec = currentUnixTimestampSec.plus(order1Lifetime); const order1ExpirationUnixTimestampSec = currentUnixTimestampSec.plus(order1Lifetime);
const order2ExpirationUnixTimestampSec = currentUnixTimestampSec.plus(order2Lifetime); const order2ExpirationUnixTimestampSec = currentUnixTimestampSec.plus(order2Lifetime);
const signedOrder1 = await fillScenarios.createFillableSignedOrderAsync( const signedOrder1 = await fillScenarios.createFillableSignedOrderAsync(
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount, makerTokenAddress,
takerTokenAddress,
makerAddress,
takerAddress,
fillableAmount,
order1ExpirationUnixTimestampSec, order1ExpirationUnixTimestampSec,
); );
const signedOrder2 = await fillScenarios.createFillableSignedOrderAsync( const signedOrder2 = await fillScenarios.createFillableSignedOrderAsync(
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount, makerTokenAddress,
takerTokenAddress,
makerAddress,
takerAddress,
fillableAmount,
order2ExpirationUnixTimestampSec, order2ExpirationUnixTimestampSec,
); );
const orderHash1 = ZeroEx.getOrderHashHex(signedOrder1); const orderHash1 = ZeroEx.getOrderHashHex(signedOrder1);

View File

@ -71,7 +71,11 @@ describe('OrderStateWatcher', () => {
describe('#removeOrder', async () => { describe('#removeOrder', async () => {
it('should successfully remove existing order', async () => { it('should successfully remove existing order', async () => {
signedOrder = await fillScenarios.createFillableSignedOrderAsync( signedOrder = await fillScenarios.createFillableSignedOrderAsync(
makerToken.address, takerToken.address, maker, taker, fillableAmount, makerToken.address,
takerToken.address,
maker,
taker,
fillableAmount,
); );
const orderHash = ZeroEx.getOrderHashHex(signedOrder); const orderHash = ZeroEx.getOrderHashHex(signedOrder);
zeroEx.orderStateWatcher.addOrder(signedOrder); zeroEx.orderStateWatcher.addOrder(signedOrder);
@ -89,10 +93,18 @@ describe('OrderStateWatcher', () => {
}); });
it('should no-op when removing a non-existing order', async () => { it('should no-op when removing a non-existing order', async () => {
signedOrder = await fillScenarios.createFillableSignedOrderAsync( signedOrder = await fillScenarios.createFillableSignedOrderAsync(
makerToken.address, takerToken.address, maker, taker, fillableAmount, makerToken.address,
takerToken.address,
maker,
taker,
fillableAmount,
); );
const orderHash = ZeroEx.getOrderHashHex(signedOrder); const orderHash = ZeroEx.getOrderHashHex(signedOrder);
const nonExistentOrderHash = `0x${orderHash.substr(2).split('').reverse().join('')}`; const nonExistentOrderHash = `0x${orderHash
.substr(2)
.split('')
.reverse()
.join('')}`;
zeroEx.orderStateWatcher.removeOrder(nonExistentOrderHash); zeroEx.orderStateWatcher.removeOrder(nonExistentOrderHash);
}); });
}); });
@ -102,8 +114,7 @@ describe('OrderStateWatcher', () => {
}); });
it('should fail when trying to subscribe twice', async () => { it('should fail when trying to subscribe twice', async () => {
zeroEx.orderStateWatcher.subscribe(_.noop); zeroEx.orderStateWatcher.subscribe(_.noop);
expect(() => zeroEx.orderStateWatcher.subscribe(_.noop)) expect(() => zeroEx.orderStateWatcher.subscribe(_.noop)).to.throw(ZeroExError.SubscriptionAlreadyPresent);
.to.throw(ZeroExError.SubscriptionAlreadyPresent);
}); });
}); });
describe('tests with cleanup', async () => { describe('tests with cleanup', async () => {
@ -115,7 +126,11 @@ describe('OrderStateWatcher', () => {
it('should emit orderStateInvalid when maker allowance set to 0 for watched order', (done: DoneCallback) => { it('should emit orderStateInvalid when maker allowance set to 0 for watched order', (done: DoneCallback) => {
(async () => { (async () => {
signedOrder = await fillScenarios.createFillableSignedOrderAsync( signedOrder = await fillScenarios.createFillableSignedOrderAsync(
makerToken.address, takerToken.address, maker, taker, fillableAmount, makerToken.address,
takerToken.address,
maker,
taker,
fillableAmount,
); );
const orderHash = ZeroEx.getOrderHashHex(signedOrder); const orderHash = ZeroEx.getOrderHashHex(signedOrder);
zeroEx.orderStateWatcher.addOrder(signedOrder); zeroEx.orderStateWatcher.addOrder(signedOrder);
@ -133,7 +148,11 @@ describe('OrderStateWatcher', () => {
it('should not emit an orderState event when irrelevant Transfer event received', (done: DoneCallback) => { it('should not emit an orderState event when irrelevant Transfer event received', (done: DoneCallback) => {
(async () => { (async () => {
signedOrder = await fillScenarios.createFillableSignedOrderAsync( signedOrder = await fillScenarios.createFillableSignedOrderAsync(
makerToken.address, takerToken.address, maker, taker, fillableAmount, makerToken.address,
takerToken.address,
maker,
taker,
fillableAmount,
); );
zeroEx.orderStateWatcher.addOrder(signedOrder); zeroEx.orderStateWatcher.addOrder(signedOrder);
const callback = reportCallbackErrors(done)((orderState: OrderState) => { const callback = reportCallbackErrors(done)((orderState: OrderState) => {
@ -152,7 +171,11 @@ describe('OrderStateWatcher', () => {
it('should emit orderStateInvalid when maker moves balance backing watched order', (done: DoneCallback) => { it('should emit orderStateInvalid when maker moves balance backing watched order', (done: DoneCallback) => {
(async () => { (async () => {
signedOrder = await fillScenarios.createFillableSignedOrderAsync( signedOrder = await fillScenarios.createFillableSignedOrderAsync(
makerToken.address, takerToken.address, maker, taker, fillableAmount, makerToken.address,
takerToken.address,
maker,
taker,
fillableAmount,
); );
const orderHash = ZeroEx.getOrderHashHex(signedOrder); const orderHash = ZeroEx.getOrderHashHex(signedOrder);
zeroEx.orderStateWatcher.addOrder(signedOrder); zeroEx.orderStateWatcher.addOrder(signedOrder);
@ -172,7 +195,11 @@ describe('OrderStateWatcher', () => {
it('should emit orderStateInvalid when watched order fully filled', (done: DoneCallback) => { it('should emit orderStateInvalid when watched order fully filled', (done: DoneCallback) => {
(async () => { (async () => {
signedOrder = await fillScenarios.createFillableSignedOrderAsync( signedOrder = await fillScenarios.createFillableSignedOrderAsync(
makerToken.address, takerToken.address, maker, taker, fillableAmount, makerToken.address,
takerToken.address,
maker,
taker,
fillableAmount,
); );
const orderHash = ZeroEx.getOrderHashHex(signedOrder); const orderHash = ZeroEx.getOrderHashHex(signedOrder);
zeroEx.orderStateWatcher.addOrder(signedOrder); zeroEx.orderStateWatcher.addOrder(signedOrder);
@ -188,14 +215,21 @@ describe('OrderStateWatcher', () => {
const shouldThrowOnInsufficientBalanceOrAllowance = true; const shouldThrowOnInsufficientBalanceOrAllowance = true;
await zeroEx.exchange.fillOrderAsync( await zeroEx.exchange.fillOrderAsync(
signedOrder, fillableAmount, shouldThrowOnInsufficientBalanceOrAllowance, taker, signedOrder,
fillableAmount,
shouldThrowOnInsufficientBalanceOrAllowance,
taker,
); );
})().catch(done); })().catch(done);
}); });
it('should emit orderStateValid when watched order partially filled', (done: DoneCallback) => { it('should emit orderStateValid when watched order partially filled', (done: DoneCallback) => {
(async () => { (async () => {
signedOrder = await fillScenarios.createFillableSignedOrderAsync( signedOrder = await fillScenarios.createFillableSignedOrderAsync(
makerToken.address, takerToken.address, maker, taker, fillableAmount, makerToken.address,
takerToken.address,
maker,
taker,
fillableAmount,
); );
const makerBalance = await zeroEx.token.getBalanceAsync(makerToken.address, maker); const makerBalance = await zeroEx.token.getBalanceAsync(makerToken.address, maker);
@ -211,16 +245,21 @@ describe('OrderStateWatcher', () => {
const remainingMakerBalance = makerBalance.sub(fillAmountInBaseUnits); const remainingMakerBalance = makerBalance.sub(fillAmountInBaseUnits);
const remainingFillable = fillableAmount.minus(fillAmountInBaseUnits); const remainingFillable = fillableAmount.minus(fillAmountInBaseUnits);
expect(orderRelevantState.remainingFillableMakerTokenAmount).to.be.bignumber.equal( expect(orderRelevantState.remainingFillableMakerTokenAmount).to.be.bignumber.equal(
remainingFillable); remainingFillable,
);
expect(orderRelevantState.remainingFillableTakerTokenAmount).to.be.bignumber.equal( expect(orderRelevantState.remainingFillableTakerTokenAmount).to.be.bignumber.equal(
remainingFillable); remainingFillable,
);
expect(orderRelevantState.makerBalance).to.be.bignumber.equal(remainingMakerBalance); expect(orderRelevantState.makerBalance).to.be.bignumber.equal(remainingMakerBalance);
done(); done();
}); });
zeroEx.orderStateWatcher.subscribe(callback); zeroEx.orderStateWatcher.subscribe(callback);
const shouldThrowOnInsufficientBalanceOrAllowance = true; const shouldThrowOnInsufficientBalanceOrAllowance = true;
await zeroEx.exchange.fillOrderAsync( await zeroEx.exchange.fillOrderAsync(
signedOrder, fillAmountInBaseUnits, shouldThrowOnInsufficientBalanceOrAllowance, taker, signedOrder,
fillAmountInBaseUnits,
shouldThrowOnInsufficientBalanceOrAllowance,
taker,
); );
})().catch(done); })().catch(done);
}); });
@ -229,8 +268,15 @@ describe('OrderStateWatcher', () => {
const makerFee = ZeroEx.toBaseUnitAmount(new BigNumber(2), 18); const makerFee = ZeroEx.toBaseUnitAmount(new BigNumber(2), 18);
const takerFee = ZeroEx.toBaseUnitAmount(new BigNumber(0), 18); const takerFee = ZeroEx.toBaseUnitAmount(new BigNumber(0), 18);
signedOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync( signedOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync(
makerToken.address, takerToken.address, makerFee, takerFee, maker, taker, fillableAmount, makerToken.address,
taker); takerToken.address,
makerFee,
takerFee,
maker,
taker,
fillableAmount,
taker,
);
const callback = reportCallbackErrors(done)((orderState: OrderState) => { const callback = reportCallbackErrors(done)((orderState: OrderState) => {
done(); done();
}); });
@ -245,7 +291,11 @@ describe('OrderStateWatcher', () => {
const takerFillableAmount = ZeroEx.toBaseUnitAmount(new BigNumber(10), decimals); const takerFillableAmount = ZeroEx.toBaseUnitAmount(new BigNumber(10), decimals);
const makerFillableAmount = ZeroEx.toBaseUnitAmount(new BigNumber(20), decimals); const makerFillableAmount = ZeroEx.toBaseUnitAmount(new BigNumber(20), decimals);
signedOrder = await fillScenarios.createAsymmetricFillableSignedOrderAsync( signedOrder = await fillScenarios.createAsymmetricFillableSignedOrderAsync(
makerToken.address, takerToken.address, maker, taker, makerFillableAmount, makerToken.address,
takerToken.address,
maker,
taker,
makerFillableAmount,
takerFillableAmount, takerFillableAmount,
); );
const fillAmountInBaseUnits = ZeroEx.toBaseUnitAmount(new BigNumber(2), decimals); const fillAmountInBaseUnits = ZeroEx.toBaseUnitAmount(new BigNumber(2), decimals);
@ -257,22 +307,31 @@ describe('OrderStateWatcher', () => {
expect(validOrderState.orderHash).to.be.equal(orderHash); expect(validOrderState.orderHash).to.be.equal(orderHash);
const orderRelevantState = validOrderState.orderRelevantState; const orderRelevantState = validOrderState.orderRelevantState;
expect(orderRelevantState.remainingFillableMakerTokenAmount).to.be.bignumber.equal( expect(orderRelevantState.remainingFillableMakerTokenAmount).to.be.bignumber.equal(
ZeroEx.toBaseUnitAmount(new BigNumber(16), decimals)); ZeroEx.toBaseUnitAmount(new BigNumber(16), decimals),
);
expect(orderRelevantState.remainingFillableTakerTokenAmount).to.be.bignumber.equal( expect(orderRelevantState.remainingFillableTakerTokenAmount).to.be.bignumber.equal(
ZeroEx.toBaseUnitAmount(new BigNumber(8), decimals)); ZeroEx.toBaseUnitAmount(new BigNumber(8), decimals),
);
done(); done();
}); });
zeroEx.orderStateWatcher.subscribe(callback); zeroEx.orderStateWatcher.subscribe(callback);
const shouldThrowOnInsufficientBalanceOrAllowance = true; const shouldThrowOnInsufficientBalanceOrAllowance = true;
await zeroEx.exchange.fillOrderAsync( await zeroEx.exchange.fillOrderAsync(
signedOrder, fillAmountInBaseUnits, shouldThrowOnInsufficientBalanceOrAllowance, taker, signedOrder,
fillAmountInBaseUnits,
shouldThrowOnInsufficientBalanceOrAllowance,
taker,
); );
})().catch(done); })().catch(done);
}); });
it('should equal approved amount when approved amount is lowest', (done: DoneCallback) => { it('should equal approved amount when approved amount is lowest', (done: DoneCallback) => {
(async () => { (async () => {
signedOrder = await fillScenarios.createFillableSignedOrderAsync( signedOrder = await fillScenarios.createFillableSignedOrderAsync(
makerToken.address, takerToken.address, maker, taker, fillableAmount, makerToken.address,
takerToken.address,
maker,
taker,
fillableAmount,
); );
const changedMakerApprovalAmount = ZeroEx.toBaseUnitAmount(new BigNumber(3), decimals); const changedMakerApprovalAmount = ZeroEx.toBaseUnitAmount(new BigNumber(3), decimals);
@ -282,9 +341,11 @@ describe('OrderStateWatcher', () => {
const validOrderState = orderState as OrderStateValid; const validOrderState = orderState as OrderStateValid;
const orderRelevantState = validOrderState.orderRelevantState; const orderRelevantState = validOrderState.orderRelevantState;
expect(orderRelevantState.remainingFillableMakerTokenAmount).to.be.bignumber.equal( expect(orderRelevantState.remainingFillableMakerTokenAmount).to.be.bignumber.equal(
changedMakerApprovalAmount); changedMakerApprovalAmount,
);
expect(orderRelevantState.remainingFillableTakerTokenAmount).to.be.bignumber.equal( expect(orderRelevantState.remainingFillableTakerTokenAmount).to.be.bignumber.equal(
changedMakerApprovalAmount); changedMakerApprovalAmount,
);
done(); done();
}); });
zeroEx.orderStateWatcher.subscribe(callback); zeroEx.orderStateWatcher.subscribe(callback);
@ -294,7 +355,11 @@ describe('OrderStateWatcher', () => {
it('should equal balance amount when balance amount is lowest', (done: DoneCallback) => { it('should equal balance amount when balance amount is lowest', (done: DoneCallback) => {
(async () => { (async () => {
signedOrder = await fillScenarios.createFillableSignedOrderAsync( signedOrder = await fillScenarios.createFillableSignedOrderAsync(
makerToken.address, takerToken.address, maker, taker, fillableAmount, makerToken.address,
takerToken.address,
maker,
taker,
fillableAmount,
); );
const makerBalance = await zeroEx.token.getBalanceAsync(makerToken.address, maker); const makerBalance = await zeroEx.token.getBalanceAsync(makerToken.address, maker);
@ -308,14 +373,15 @@ describe('OrderStateWatcher', () => {
const validOrderState = orderState as OrderStateValid; const validOrderState = orderState as OrderStateValid;
const orderRelevantState = validOrderState.orderRelevantState; const orderRelevantState = validOrderState.orderRelevantState;
expect(orderRelevantState.remainingFillableMakerTokenAmount).to.be.bignumber.equal( expect(orderRelevantState.remainingFillableMakerTokenAmount).to.be.bignumber.equal(
remainingAmount); remainingAmount,
);
expect(orderRelevantState.remainingFillableTakerTokenAmount).to.be.bignumber.equal( expect(orderRelevantState.remainingFillableTakerTokenAmount).to.be.bignumber.equal(
remainingAmount); remainingAmount,
);
done(); done();
}); });
zeroEx.orderStateWatcher.subscribe(callback); zeroEx.orderStateWatcher.subscribe(callback);
await zeroEx.token.transferAsync( await zeroEx.token.transferAsync(makerToken.address, maker, ZeroEx.NULL_ADDRESS, transferAmount);
makerToken.address, maker, ZeroEx.NULL_ADDRESS, transferAmount);
})().catch(done); })().catch(done);
}); });
it('should equal remaining amount when partially cancelled and order has fees', (done: DoneCallback) => { it('should equal remaining amount when partially cancelled and order has fees', (done: DoneCallback) => {
@ -324,8 +390,15 @@ describe('OrderStateWatcher', () => {
const makerFee = ZeroEx.toBaseUnitAmount(new BigNumber(5), decimals); const makerFee = ZeroEx.toBaseUnitAmount(new BigNumber(5), decimals);
const feeRecipient = taker; const feeRecipient = taker;
signedOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync( signedOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync(
makerToken.address, takerToken.address, makerFee, takerFee, maker, makerToken.address,
taker, fillableAmount, feeRecipient); takerToken.address,
makerFee,
takerFee,
maker,
taker,
fillableAmount,
feeRecipient,
);
const remainingTokenAmount = ZeroEx.toBaseUnitAmount(new BigNumber(4), decimals); const remainingTokenAmount = ZeroEx.toBaseUnitAmount(new BigNumber(4), decimals);
const transferTokenAmount = makerFee.sub(remainingTokenAmount); const transferTokenAmount = makerFee.sub(remainingTokenAmount);
@ -336,7 +409,8 @@ describe('OrderStateWatcher', () => {
const validOrderState = orderState as OrderStateValid; const validOrderState = orderState as OrderStateValid;
const orderRelevantState = validOrderState.orderRelevantState; const orderRelevantState = validOrderState.orderRelevantState;
expect(orderRelevantState.remainingFillableMakerTokenAmount).to.be.bignumber.equal( expect(orderRelevantState.remainingFillableMakerTokenAmount).to.be.bignumber.equal(
remainingTokenAmount); remainingTokenAmount,
);
done(); done();
}); });
zeroEx.orderStateWatcher.subscribe(callback); zeroEx.orderStateWatcher.subscribe(callback);
@ -349,8 +423,15 @@ describe('OrderStateWatcher', () => {
const makerFee = ZeroEx.toBaseUnitAmount(new BigNumber(5), decimals); const makerFee = ZeroEx.toBaseUnitAmount(new BigNumber(5), decimals);
const feeRecipient = taker; const feeRecipient = taker;
signedOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync( signedOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync(
makerToken.address, takerToken.address, makerFee, takerFee, maker, makerToken.address,
taker, fillableAmount, feeRecipient); takerToken.address,
makerFee,
takerFee,
maker,
taker,
fillableAmount,
feeRecipient,
);
const remainingFeeAmount = ZeroEx.toBaseUnitAmount(new BigNumber(3), decimals); const remainingFeeAmount = ZeroEx.toBaseUnitAmount(new BigNumber(3), decimals);
@ -362,13 +443,18 @@ describe('OrderStateWatcher', () => {
const validOrderState = orderState as OrderStateValid; const validOrderState = orderState as OrderStateValid;
const orderRelevantState = validOrderState.orderRelevantState; const orderRelevantState = validOrderState.orderRelevantState;
expect(orderRelevantState.remainingFillableMakerTokenAmount).to.be.bignumber.equal( expect(orderRelevantState.remainingFillableMakerTokenAmount).to.be.bignumber.equal(
remainingFeeAmount); remainingFeeAmount,
);
done(); done();
}); });
zeroEx.orderStateWatcher.subscribe(callback); zeroEx.orderStateWatcher.subscribe(callback);
await zeroEx.token.setProxyAllowanceAsync(zrxTokenAddress, maker, remainingFeeAmount); await zeroEx.token.setProxyAllowanceAsync(zrxTokenAddress, maker, remainingFeeAmount);
await zeroEx.token.transferAsync( await zeroEx.token.transferAsync(
makerToken.address, maker, ZeroEx.NULL_ADDRESS, transferTokenAmount); makerToken.address,
maker,
ZeroEx.NULL_ADDRESS,
transferTokenAmount,
);
})().catch(done); })().catch(done);
}); });
it('should calculate full amount when all available and non-divisible', (done: DoneCallback) => { it('should calculate full amount when all available and non-divisible', (done: DoneCallback) => {
@ -377,8 +463,15 @@ describe('OrderStateWatcher', () => {
const makerFee = ZeroEx.toBaseUnitAmount(new BigNumber(2), decimals); const makerFee = ZeroEx.toBaseUnitAmount(new BigNumber(2), decimals);
const feeRecipient = taker; const feeRecipient = taker;
signedOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync( signedOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync(
makerToken.address, takerToken.address, makerFee, takerFee, maker, makerToken.address,
taker, fillableAmount, feeRecipient); takerToken.address,
makerFee,
takerFee,
maker,
taker,
fillableAmount,
feeRecipient,
);
zeroEx.orderStateWatcher.addOrder(signedOrder); zeroEx.orderStateWatcher.addOrder(signedOrder);
@ -386,19 +479,27 @@ describe('OrderStateWatcher', () => {
const validOrderState = orderState as OrderStateValid; const validOrderState = orderState as OrderStateValid;
const orderRelevantState = validOrderState.orderRelevantState; const orderRelevantState = validOrderState.orderRelevantState;
expect(orderRelevantState.remainingFillableMakerTokenAmount).to.be.bignumber.equal( expect(orderRelevantState.remainingFillableMakerTokenAmount).to.be.bignumber.equal(
fillableAmount); fillableAmount,
);
done(); done();
}); });
zeroEx.orderStateWatcher.subscribe(callback); zeroEx.orderStateWatcher.subscribe(callback);
await zeroEx.token.setProxyAllowanceAsync( await zeroEx.token.setProxyAllowanceAsync(
makerToken.address, maker, ZeroEx.toBaseUnitAmount(new BigNumber(100), decimals)); makerToken.address,
maker,
ZeroEx.toBaseUnitAmount(new BigNumber(100), decimals),
);
})().catch(done); })().catch(done);
}); });
}); });
it('should emit orderStateInvalid when watched order cancelled', (done: DoneCallback) => { it('should emit orderStateInvalid when watched order cancelled', (done: DoneCallback) => {
(async () => { (async () => {
signedOrder = await fillScenarios.createFillableSignedOrderAsync( signedOrder = await fillScenarios.createFillableSignedOrderAsync(
makerToken.address, takerToken.address, maker, taker, fillableAmount, makerToken.address,
takerToken.address,
maker,
taker,
fillableAmount,
); );
const orderHash = ZeroEx.getOrderHashHex(signedOrder); const orderHash = ZeroEx.getOrderHashHex(signedOrder);
zeroEx.orderStateWatcher.addOrder(signedOrder); zeroEx.orderStateWatcher.addOrder(signedOrder);
@ -419,7 +520,11 @@ describe('OrderStateWatcher', () => {
(async () => { (async () => {
const remainingFillableAmountInBaseUnits = new BigNumber(100); const remainingFillableAmountInBaseUnits = new BigNumber(100);
signedOrder = await fillScenarios.createFillableSignedOrderAsync( signedOrder = await fillScenarios.createFillableSignedOrderAsync(
makerToken.address, takerToken.address, maker, taker, fillableAmount, makerToken.address,
takerToken.address,
maker,
taker,
fillableAmount,
); );
const orderHash = ZeroEx.getOrderHashHex(signedOrder); const orderHash = ZeroEx.getOrderHashHex(signedOrder);
zeroEx.orderStateWatcher.addOrder(signedOrder); zeroEx.orderStateWatcher.addOrder(signedOrder);
@ -433,14 +538,19 @@ describe('OrderStateWatcher', () => {
}); });
zeroEx.orderStateWatcher.subscribe(callback); zeroEx.orderStateWatcher.subscribe(callback);
await zeroEx.exchange.cancelOrderAsync( await zeroEx.exchange.cancelOrderAsync(
signedOrder, fillableAmount.minus(remainingFillableAmountInBaseUnits), signedOrder,
fillableAmount.minus(remainingFillableAmountInBaseUnits),
); );
})().catch(done); })().catch(done);
}); });
it('should emit orderStateValid when watched order partially cancelled', (done: DoneCallback) => { it('should emit orderStateValid when watched order partially cancelled', (done: DoneCallback) => {
(async () => { (async () => {
signedOrder = await fillScenarios.createFillableSignedOrderAsync( signedOrder = await fillScenarios.createFillableSignedOrderAsync(
makerToken.address, takerToken.address, maker, taker, fillableAmount, makerToken.address,
takerToken.address,
maker,
taker,
fillableAmount,
); );
const cancelAmountInBaseUnits = new BigNumber(2); const cancelAmountInBaseUnits = new BigNumber(2);

View File

@ -62,108 +62,152 @@ describe('OrderValidation', () => {
describe('validateOrderFillableOrThrowAsync', () => { describe('validateOrderFillableOrThrowAsync', () => {
it('should succeed if the order is fillable', async () => { it('should succeed if the order is fillable', async () => {
const signedOrder = await fillScenarios.createFillableSignedOrderAsync( const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount, makerTokenAddress,
); takerTokenAddress,
await zeroEx.exchange.validateOrderFillableOrThrowAsync( makerAddress,
signedOrder, takerAddress,
fillableAmount,
); );
await zeroEx.exchange.validateOrderFillableOrThrowAsync(signedOrder);
}); });
it('should succeed if the order is asymmetric and fillable', async () => { it('should succeed if the order is asymmetric and fillable', async () => {
const makerFillableAmount = fillableAmount; const makerFillableAmount = fillableAmount;
const takerFillableAmount = fillableAmount.minus(4); const takerFillableAmount = fillableAmount.minus(4);
const signedOrder = await fillScenarios.createAsymmetricFillableSignedOrderAsync( const signedOrder = await fillScenarios.createAsymmetricFillableSignedOrderAsync(
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, makerTokenAddress,
makerFillableAmount, takerFillableAmount, takerTokenAddress,
); makerAddress,
await zeroEx.exchange.validateOrderFillableOrThrowAsync( takerAddress,
signedOrder, makerFillableAmount,
takerFillableAmount,
); );
await zeroEx.exchange.validateOrderFillableOrThrowAsync(signedOrder);
}); });
it('should throw when the order is fully filled or cancelled', async () => { it('should throw when the order is fully filled or cancelled', async () => {
const signedOrder = await fillScenarios.createFillableSignedOrderAsync( const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount, makerTokenAddress,
takerTokenAddress,
makerAddress,
takerAddress,
fillableAmount,
); );
await zeroEx.exchange.cancelOrderAsync(signedOrder, fillableAmount); await zeroEx.exchange.cancelOrderAsync(signedOrder, fillableAmount);
return expect(zeroEx.exchange.validateOrderFillableOrThrowAsync( return expect(zeroEx.exchange.validateOrderFillableOrThrowAsync(signedOrder)).to.be.rejectedWith(
signedOrder, ExchangeContractErrs.OrderRemainingFillAmountZero,
)).to.be.rejectedWith(ExchangeContractErrs.OrderRemainingFillAmountZero); );
}); });
it('should throw when order is expired', async () => { it('should throw when order is expired', async () => {
const expirationInPast = new BigNumber(1496826058); // 7th Jun 2017 const expirationInPast = new BigNumber(1496826058); // 7th Jun 2017
const signedOrder = await fillScenarios.createFillableSignedOrderAsync( const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, makerTokenAddress,
fillableAmount, expirationInPast, takerTokenAddress,
makerAddress,
takerAddress,
fillableAmount,
expirationInPast,
);
return expect(zeroEx.exchange.validateOrderFillableOrThrowAsync(signedOrder)).to.be.rejectedWith(
ExchangeContractErrs.OrderFillExpired,
); );
return expect(zeroEx.exchange.validateOrderFillableOrThrowAsync(
signedOrder,
)).to.be.rejectedWith(ExchangeContractErrs.OrderFillExpired);
}); });
}); });
describe('validateFillOrderAndThrowIfInvalidAsync', () => { describe('validateFillOrderAndThrowIfInvalidAsync', () => {
it('should throw when the fill amount is zero', async () => { it('should throw when the fill amount is zero', async () => {
const signedOrder = await fillScenarios.createFillableSignedOrderAsync( const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount, makerTokenAddress,
takerTokenAddress,
makerAddress,
takerAddress,
fillableAmount,
); );
const zeroFillAmount = new BigNumber(0); const zeroFillAmount = new BigNumber(0);
return expect(zeroEx.exchange.validateFillOrderThrowIfInvalidAsync( return expect(
signedOrder, zeroFillAmount, takerAddress, zeroEx.exchange.validateFillOrderThrowIfInvalidAsync(signedOrder, zeroFillAmount, takerAddress),
)).to.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero); ).to.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero);
}); });
it('should throw when the signature is invalid', async () => { it('should throw when the signature is invalid', async () => {
const signedOrder = await fillScenarios.createFillableSignedOrderAsync( const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount, makerTokenAddress,
takerTokenAddress,
makerAddress,
takerAddress,
fillableAmount,
); );
// 27 <--> 28 // 27 <--> 28
signedOrder.ecSignature.v = (28 - signedOrder.ecSignature.v) + 27; signedOrder.ecSignature.v = 28 - signedOrder.ecSignature.v + 27;
return expect(zeroEx.exchange.validateFillOrderThrowIfInvalidAsync( return expect(
signedOrder, fillableAmount, takerAddress, zeroEx.exchange.validateFillOrderThrowIfInvalidAsync(signedOrder, fillableAmount, takerAddress),
)).to.be.rejectedWith(ZeroExError.InvalidSignature); ).to.be.rejectedWith(ZeroExError.InvalidSignature);
}); });
it('should throw when the order is fully filled or cancelled', async () => { it('should throw when the order is fully filled or cancelled', async () => {
const signedOrder = await fillScenarios.createFillableSignedOrderAsync( const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount, makerTokenAddress,
takerTokenAddress,
makerAddress,
takerAddress,
fillableAmount,
); );
await zeroEx.exchange.cancelOrderAsync(signedOrder, fillableAmount); await zeroEx.exchange.cancelOrderAsync(signedOrder, fillableAmount);
return expect(zeroEx.exchange.validateFillOrderThrowIfInvalidAsync( return expect(
signedOrder, fillableAmount, takerAddress, zeroEx.exchange.validateFillOrderThrowIfInvalidAsync(signedOrder, fillableAmount, takerAddress),
)).to.be.rejectedWith(ExchangeContractErrs.OrderRemainingFillAmountZero); ).to.be.rejectedWith(ExchangeContractErrs.OrderRemainingFillAmountZero);
}); });
it('should throw when sender is not a taker', async () => { it('should throw when sender is not a taker', async () => {
const signedOrder = await fillScenarios.createFillableSignedOrderAsync( const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount, makerTokenAddress,
takerTokenAddress,
makerAddress,
takerAddress,
fillableAmount,
); );
const nonTakerAddress = userAddresses[6]; const nonTakerAddress = userAddresses[6];
return expect(zeroEx.exchange.validateFillOrderThrowIfInvalidAsync( return expect(
signedOrder, fillTakerAmount, nonTakerAddress, zeroEx.exchange.validateFillOrderThrowIfInvalidAsync(signedOrder, fillTakerAmount, nonTakerAddress),
)).to.be.rejectedWith(ExchangeContractErrs.TransactionSenderIsNotFillOrderTaker); ).to.be.rejectedWith(ExchangeContractErrs.TransactionSenderIsNotFillOrderTaker);
}); });
it('should throw when order is expired', async () => { it('should throw when order is expired', async () => {
const expirationInPast = new BigNumber(1496826058); // 7th Jun 2017 const expirationInPast = new BigNumber(1496826058); // 7th Jun 2017
const signedOrder = await fillScenarios.createFillableSignedOrderAsync( const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, makerTokenAddress,
fillableAmount, expirationInPast, takerTokenAddress,
makerAddress,
takerAddress,
fillableAmount,
expirationInPast,
); );
return expect(zeroEx.exchange.validateFillOrderThrowIfInvalidAsync( return expect(
signedOrder, fillTakerAmount, takerAddress, zeroEx.exchange.validateFillOrderThrowIfInvalidAsync(signedOrder, fillTakerAmount, takerAddress),
)).to.be.rejectedWith(ExchangeContractErrs.OrderFillExpired); ).to.be.rejectedWith(ExchangeContractErrs.OrderFillExpired);
}); });
it('should throw when there a rounding error would have occurred', async () => { it('should throw when there a rounding error would have occurred', async () => {
const makerAmount = new BigNumber(3); const makerAmount = new BigNumber(3);
const takerAmount = new BigNumber(5); const takerAmount = new BigNumber(5);
const signedOrder = await fillScenarios.createAsymmetricFillableSignedOrderAsync( const signedOrder = await fillScenarios.createAsymmetricFillableSignedOrderAsync(
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, makerTokenAddress,
makerAmount, takerAmount, takerTokenAddress,
makerAddress,
takerAddress,
makerAmount,
takerAmount,
); );
const fillTakerAmountThatCausesRoundingError = new BigNumber(3); const fillTakerAmountThatCausesRoundingError = new BigNumber(3);
return expect(zeroEx.exchange.validateFillOrderThrowIfInvalidAsync( return expect(
signedOrder, fillTakerAmountThatCausesRoundingError, takerAddress, zeroEx.exchange.validateFillOrderThrowIfInvalidAsync(
)).to.be.rejectedWith(ExchangeContractErrs.OrderFillRoundingError); signedOrder,
fillTakerAmountThatCausesRoundingError,
takerAddress,
),
).to.be.rejectedWith(ExchangeContractErrs.OrderFillRoundingError);
}); });
}); });
describe('#validateFillOrKillOrderAndThrowIfInvalidAsync', () => { describe('#validateFillOrKillOrderAndThrowIfInvalidAsync', () => {
it('should throw if remaining fillAmount is less then the desired fillAmount', async () => { it('should throw if remaining fillAmount is less then the desired fillAmount', async () => {
const signedOrder = await fillScenarios.createFillableSignedOrderAsync( const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount, makerTokenAddress,
takerTokenAddress,
makerAddress,
takerAddress,
fillableAmount,
); );
const tooLargeFillAmount = new BigNumber(7); const tooLargeFillAmount = new BigNumber(7);
const fillAmountDifference = tooLargeFillAmount.minus(fillableAmount); const fillAmountDifference = tooLargeFillAmount.minus(fillableAmount);
@ -172,9 +216,13 @@ describe('OrderValidation', () => {
await zeroEx.token.transferAsync(makerTokenAddress, coinbase, makerAddress, fillAmountDifference); await zeroEx.token.transferAsync(makerTokenAddress, coinbase, makerAddress, fillAmountDifference);
await zeroEx.token.setProxyAllowanceAsync(makerTokenAddress, makerAddress, tooLargeFillAmount); await zeroEx.token.setProxyAllowanceAsync(makerTokenAddress, makerAddress, tooLargeFillAmount);
return expect(zeroEx.exchange.validateFillOrKillOrderThrowIfInvalidAsync( return expect(
signedOrder, tooLargeFillAmount, takerAddress, zeroEx.exchange.validateFillOrKillOrderThrowIfInvalidAsync(
)).to.be.rejectedWith(ExchangeContractErrs.InsufficientRemainingFillAmount); signedOrder,
tooLargeFillAmount,
takerAddress,
),
).to.be.rejectedWith(ExchangeContractErrs.InsufficientRemainingFillAmount);
}); });
}); });
describe('validateCancelOrderAndThrowIfInvalidAsync', () => { describe('validateCancelOrderAndThrowIfInvalidAsync', () => {
@ -186,27 +234,38 @@ describe('OrderValidation', () => {
makerTokenAddress = makerToken.address; makerTokenAddress = makerToken.address;
takerTokenAddress = takerToken.address; takerTokenAddress = takerToken.address;
signedOrder = await fillScenarios.createFillableSignedOrderAsync( signedOrder = await fillScenarios.createFillableSignedOrderAsync(
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount, makerTokenAddress,
takerTokenAddress,
makerAddress,
takerAddress,
fillableAmount,
); );
}); });
it('should throw when cancel amount is zero', async () => { it('should throw when cancel amount is zero', async () => {
const zeroCancelAmount = new BigNumber(0); const zeroCancelAmount = new BigNumber(0);
return expect(zeroEx.exchange.validateCancelOrderThrowIfInvalidAsync(signedOrder, zeroCancelAmount)) return expect(
.to.be.rejectedWith(ExchangeContractErrs.OrderCancelAmountZero); zeroEx.exchange.validateCancelOrderThrowIfInvalidAsync(signedOrder, zeroCancelAmount),
).to.be.rejectedWith(ExchangeContractErrs.OrderCancelAmountZero);
}); });
it('should throw when order is expired', async () => { it('should throw when order is expired', async () => {
const expirationInPast = new BigNumber(1496826058); // 7th Jun 2017 const expirationInPast = new BigNumber(1496826058); // 7th Jun 2017
const expiredSignedOrder = await fillScenarios.createFillableSignedOrderAsync( const expiredSignedOrder = await fillScenarios.createFillableSignedOrderAsync(
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, makerTokenAddress,
fillableAmount, expirationInPast, takerTokenAddress,
makerAddress,
takerAddress,
fillableAmount,
expirationInPast,
); );
return expect(zeroEx.exchange.validateCancelOrderThrowIfInvalidAsync(expiredSignedOrder, cancelAmount)) return expect(
.to.be.rejectedWith(ExchangeContractErrs.OrderCancelExpired); zeroEx.exchange.validateCancelOrderThrowIfInvalidAsync(expiredSignedOrder, cancelAmount),
).to.be.rejectedWith(ExchangeContractErrs.OrderCancelExpired);
}); });
it('should throw when order is already cancelled or filled', async () => { it('should throw when order is already cancelled or filled', async () => {
await zeroEx.exchange.cancelOrderAsync(signedOrder, fillableAmount); await zeroEx.exchange.cancelOrderAsync(signedOrder, fillableAmount);
return expect(zeroEx.exchange.validateCancelOrderThrowIfInvalidAsync(signedOrder, fillableAmount)) return expect(
.to.be.rejectedWith(ExchangeContractErrs.OrderAlreadyCancelledOrFilled); zeroEx.exchange.validateCancelOrderThrowIfInvalidAsync(signedOrder, fillableAmount),
).to.be.rejectedWith(ExchangeContractErrs.OrderAlreadyCancelledOrFilled);
}); });
}); });
describe('#validateFillOrderBalancesAllowancesThrowIfInvalidAsync', () => { describe('#validateFillOrderBalancesAllowancesThrowIfInvalidAsync', () => {
@ -224,35 +283,69 @@ describe('OrderValidation', () => {
const makerFee = new BigNumber(2); const makerFee = new BigNumber(2);
const takerFee = new BigNumber(2); const takerFee = new BigNumber(2);
const signedOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync( const signedOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync(
makerTokenAddress, takerTokenAddress, makerFee, takerFee, makerTokenAddress,
makerAddress, takerAddress, fillableAmount, feeRecipient, takerTokenAddress,
makerFee,
takerFee,
makerAddress,
takerAddress,
fillableAmount,
feeRecipient,
); );
await OrderValidationUtils.validateFillOrderBalancesAllowancesThrowIfInvalidAsync( await OrderValidationUtils.validateFillOrderBalancesAllowancesThrowIfInvalidAsync(
exchangeTransferSimulator, signedOrder, fillableAmount, takerAddress, zrxTokenAddress, exchangeTransferSimulator,
signedOrder,
fillableAmount,
takerAddress,
zrxTokenAddress,
); );
expect(transferFromAsync.callCount).to.be.equal(4); expect(transferFromAsync.callCount).to.be.equal(4);
expect( expect(
transferFromAsync.getCall(0).calledWith( transferFromAsync
makerTokenAddress, makerAddress, takerAddress, bigNumberMatch(fillableAmount), .getCall(0)
TradeSide.Maker, TransferType.Trade, .calledWith(
makerTokenAddress,
makerAddress,
takerAddress,
bigNumberMatch(fillableAmount),
TradeSide.Maker,
TransferType.Trade,
), ),
).to.be.true(); ).to.be.true();
expect( expect(
transferFromAsync.getCall(1).calledWith( transferFromAsync
takerTokenAddress, takerAddress, makerAddress, bigNumberMatch(fillableAmount), .getCall(1)
TradeSide.Taker, TransferType.Trade, .calledWith(
takerTokenAddress,
takerAddress,
makerAddress,
bigNumberMatch(fillableAmount),
TradeSide.Taker,
TransferType.Trade,
), ),
).to.be.true(); ).to.be.true();
expect( expect(
transferFromAsync.getCall(2).calledWith( transferFromAsync
zrxTokenAddress, makerAddress, feeRecipient, bigNumberMatch(makerFee), .getCall(2)
TradeSide.Maker, TransferType.Fee, .calledWith(
zrxTokenAddress,
makerAddress,
feeRecipient,
bigNumberMatch(makerFee),
TradeSide.Maker,
TransferType.Fee,
), ),
).to.be.true(); ).to.be.true();
expect( expect(
transferFromAsync.getCall(3).calledWith( transferFromAsync
zrxTokenAddress, takerAddress, feeRecipient, bigNumberMatch(takerFee), .getCall(3)
TradeSide.Taker, TransferType.Fee, .calledWith(
zrxTokenAddress,
takerAddress,
feeRecipient,
bigNumberMatch(takerFee),
TradeSide.Taker,
TransferType.Fee,
), ),
).to.be.true(); ).to.be.true();
}); });
@ -260,35 +353,69 @@ describe('OrderValidation', () => {
const makerFee = new BigNumber(2); const makerFee = new BigNumber(2);
const takerFee = new BigNumber(2); const takerFee = new BigNumber(2);
const signedOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync( const signedOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync(
makerTokenAddress, takerTokenAddress, makerFee, takerFee, makerTokenAddress,
makerAddress, ZeroEx.NULL_ADDRESS, fillableAmount, feeRecipient, takerTokenAddress,
makerFee,
takerFee,
makerAddress,
ZeroEx.NULL_ADDRESS,
fillableAmount,
feeRecipient,
); );
await OrderValidationUtils.validateFillOrderBalancesAllowancesThrowIfInvalidAsync( await OrderValidationUtils.validateFillOrderBalancesAllowancesThrowIfInvalidAsync(
exchangeTransferSimulator, signedOrder, fillableAmount, takerAddress, zrxTokenAddress, exchangeTransferSimulator,
signedOrder,
fillableAmount,
takerAddress,
zrxTokenAddress,
); );
expect(transferFromAsync.callCount).to.be.equal(4); expect(transferFromAsync.callCount).to.be.equal(4);
expect( expect(
transferFromAsync.getCall(0).calledWith( transferFromAsync
makerTokenAddress, makerAddress, takerAddress, bigNumberMatch(fillableAmount), .getCall(0)
TradeSide.Maker, TransferType.Trade, .calledWith(
makerTokenAddress,
makerAddress,
takerAddress,
bigNumberMatch(fillableAmount),
TradeSide.Maker,
TransferType.Trade,
), ),
).to.be.true(); ).to.be.true();
expect( expect(
transferFromAsync.getCall(1).calledWith( transferFromAsync
takerTokenAddress, takerAddress, makerAddress, bigNumberMatch(fillableAmount), .getCall(1)
TradeSide.Taker, TransferType.Trade, .calledWith(
takerTokenAddress,
takerAddress,
makerAddress,
bigNumberMatch(fillableAmount),
TradeSide.Taker,
TransferType.Trade,
), ),
).to.be.true(); ).to.be.true();
expect( expect(
transferFromAsync.getCall(2).calledWith( transferFromAsync
zrxTokenAddress, makerAddress, feeRecipient, bigNumberMatch(makerFee), .getCall(2)
TradeSide.Maker, TransferType.Fee, .calledWith(
zrxTokenAddress,
makerAddress,
feeRecipient,
bigNumberMatch(makerFee),
TradeSide.Maker,
TransferType.Fee,
), ),
).to.be.true(); ).to.be.true();
expect( expect(
transferFromAsync.getCall(3).calledWith( transferFromAsync
zrxTokenAddress, takerAddress, feeRecipient, bigNumberMatch(takerFee), .getCall(3)
TradeSide.Taker, TransferType.Fee, .calledWith(
zrxTokenAddress,
takerAddress,
feeRecipient,
bigNumberMatch(takerFee),
TradeSide.Taker,
TransferType.Fee,
), ),
).to.be.true(); ).to.be.true();
}); });
@ -296,10 +423,19 @@ describe('OrderValidation', () => {
const makerTokenAmount = new BigNumber(3); const makerTokenAmount = new BigNumber(3);
const takerTokenAmount = new BigNumber(1); const takerTokenAmount = new BigNumber(1);
const signedOrder = await fillScenarios.createAsymmetricFillableSignedOrderAsync( const signedOrder = await fillScenarios.createAsymmetricFillableSignedOrderAsync(
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, makerTokenAmount, takerTokenAmount, makerTokenAddress,
takerTokenAddress,
makerAddress,
takerAddress,
makerTokenAmount,
takerTokenAmount,
); );
await OrderValidationUtils.validateFillOrderBalancesAllowancesThrowIfInvalidAsync( await OrderValidationUtils.validateFillOrderBalancesAllowancesThrowIfInvalidAsync(
exchangeTransferSimulator, signedOrder, takerTokenAmount, takerAddress, zrxTokenAddress, exchangeTransferSimulator,
signedOrder,
takerTokenAmount,
takerAddress,
zrxTokenAddress,
); );
expect(transferFromAsync.callCount).to.be.equal(4); expect(transferFromAsync.callCount).to.be.equal(4);
const makerFillAmount = transferFromAsync.getCall(0).args[3]; const makerFillAmount = transferFromAsync.getCall(0).args[3];
@ -309,12 +445,22 @@ describe('OrderValidation', () => {
const makerFee = new BigNumber(2); const makerFee = new BigNumber(2);
const takerFee = new BigNumber(4); const takerFee = new BigNumber(4);
const signedOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync( const signedOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync(
makerTokenAddress, takerTokenAddress, makerFee, takerFee, makerAddress, takerAddress, makerTokenAddress,
fillableAmount, ZeroEx.NULL_ADDRESS, takerTokenAddress,
makerFee,
takerFee,
makerAddress,
takerAddress,
fillableAmount,
ZeroEx.NULL_ADDRESS,
); );
const fillTakerTokenAmount = fillableAmount.div(2).round(0); const fillTakerTokenAmount = fillableAmount.div(2).round(0);
await OrderValidationUtils.validateFillOrderBalancesAllowancesThrowIfInvalidAsync( await OrderValidationUtils.validateFillOrderBalancesAllowancesThrowIfInvalidAsync(
exchangeTransferSimulator, signedOrder, fillTakerTokenAmount, takerAddress, zrxTokenAddress, exchangeTransferSimulator,
signedOrder,
fillTakerTokenAmount,
takerAddress,
zrxTokenAddress,
); );
const makerPartialFee = makerFee.div(2); const makerPartialFee = makerFee.div(2);
const takerPartialFee = takerFee.div(2); const takerPartialFee = takerFee.div(2);

View File

@ -28,15 +28,19 @@ describe('RemainingFillableCalculator', () => {
const zeroAddress = '0x0'; const zeroAddress = '0x0';
const signature: ECSignature = { v: 27, r: '', s: '' }; const signature: ECSignature = { v: 27, r: '', s: '' };
beforeEach(async () => { beforeEach(async () => {
[makerAmount, takerAmount, makerFeeAmount] = [ZeroEx.toBaseUnitAmount(new BigNumber(50), decimals), [makerAmount, takerAmount, makerFeeAmount] = [
ZeroEx.toBaseUnitAmount(new BigNumber(50), decimals),
ZeroEx.toBaseUnitAmount(new BigNumber(5), decimals), ZeroEx.toBaseUnitAmount(new BigNumber(5), decimals),
ZeroEx.toBaseUnitAmount(new BigNumber(1), decimals)]; ZeroEx.toBaseUnitAmount(new BigNumber(1), decimals),
];
[transferrableMakerTokenAmount, transferrableMakerFeeTokenAmount] = [ [transferrableMakerTokenAmount, transferrableMakerFeeTokenAmount] = [
ZeroEx.toBaseUnitAmount(new BigNumber(50), decimals), ZeroEx.toBaseUnitAmount(new BigNumber(50), decimals),
ZeroEx.toBaseUnitAmount(new BigNumber(5), decimals)]; ZeroEx.toBaseUnitAmount(new BigNumber(5), decimals),
];
}); });
function buildSignedOrder(): SignedOrder { function buildSignedOrder(): SignedOrder {
return { ecSignature: signature, return {
ecSignature: signature,
exchangeContractAddress: zeroAddress, exchangeContractAddress: zeroAddress,
feeRecipient: zeroAddress, feeRecipient: zeroAddress,
maker: zeroAddress, maker: zeroAddress,
@ -48,7 +52,8 @@ describe('RemainingFillableCalculator', () => {
makerTokenAddress: makerToken, makerTokenAddress: makerToken,
takerTokenAddress: takerToken, takerTokenAddress: takerToken,
salt: zero, salt: zero,
expirationUnixTimestampSec: zero }; expirationUnixTimestampSec: zero,
};
} }
describe('Maker token is NOT ZRX', () => { describe('Maker token is NOT ZRX', () => {
before(async () => { before(async () => {
@ -57,23 +62,38 @@ describe('RemainingFillableCalculator', () => {
it('calculates the correct amount when unfilled and funds available', () => { it('calculates the correct amount when unfilled and funds available', () => {
signedOrder = buildSignedOrder(); signedOrder = buildSignedOrder();
remainingMakerTokenAmount = signedOrder.makerTokenAmount; remainingMakerTokenAmount = signedOrder.makerTokenAmount;
calculator = new RemainingFillableCalculator(signedOrder, isMakerTokenZRX, calculator = new RemainingFillableCalculator(
transferrableMakerTokenAmount, transferrableMakerFeeTokenAmount, remainingMakerTokenAmount); signedOrder,
isMakerTokenZRX,
transferrableMakerTokenAmount,
transferrableMakerFeeTokenAmount,
remainingMakerTokenAmount,
);
expect(calculator.computeRemainingMakerFillable()).to.be.bignumber.equal(remainingMakerTokenAmount); expect(calculator.computeRemainingMakerFillable()).to.be.bignumber.equal(remainingMakerTokenAmount);
}); });
it('calculates the correct amount when partially filled and funds available', () => { it('calculates the correct amount when partially filled and funds available', () => {
signedOrder = buildSignedOrder(); signedOrder = buildSignedOrder();
remainingMakerTokenAmount = ZeroEx.toBaseUnitAmount(new BigNumber(1), decimals); remainingMakerTokenAmount = ZeroEx.toBaseUnitAmount(new BigNumber(1), decimals);
calculator = new RemainingFillableCalculator(signedOrder, isMakerTokenZRX, calculator = new RemainingFillableCalculator(
transferrableMakerTokenAmount, transferrableMakerFeeTokenAmount, remainingMakerTokenAmount); signedOrder,
isMakerTokenZRX,
transferrableMakerTokenAmount,
transferrableMakerFeeTokenAmount,
remainingMakerTokenAmount,
);
expect(calculator.computeRemainingMakerFillable()).to.be.bignumber.equal(remainingMakerTokenAmount); expect(calculator.computeRemainingMakerFillable()).to.be.bignumber.equal(remainingMakerTokenAmount);
}); });
it('calculates the amount to be 0 when all fee funds are transferred', () => { it('calculates the amount to be 0 when all fee funds are transferred', () => {
signedOrder = buildSignedOrder(); signedOrder = buildSignedOrder();
transferrableMakerFeeTokenAmount = zero; transferrableMakerFeeTokenAmount = zero;
remainingMakerTokenAmount = signedOrder.makerTokenAmount; remainingMakerTokenAmount = signedOrder.makerTokenAmount;
calculator = new RemainingFillableCalculator(signedOrder, isMakerTokenZRX, calculator = new RemainingFillableCalculator(
transferrableMakerTokenAmount, transferrableMakerFeeTokenAmount, remainingMakerTokenAmount); signedOrder,
isMakerTokenZRX,
transferrableMakerTokenAmount,
transferrableMakerFeeTokenAmount,
remainingMakerTokenAmount,
);
expect(calculator.computeRemainingMakerFillable()).to.be.bignumber.equal(zero); expect(calculator.computeRemainingMakerFillable()).to.be.bignumber.equal(zero);
}); });
it('calculates the correct amount when balance is less than remaining fillable', () => { it('calculates the correct amount when balance is less than remaining fillable', () => {
@ -81,41 +101,58 @@ describe('RemainingFillableCalculator', () => {
const partiallyFilledAmount = ZeroEx.toBaseUnitAmount(new BigNumber(2), decimals); const partiallyFilledAmount = ZeroEx.toBaseUnitAmount(new BigNumber(2), decimals);
remainingMakerTokenAmount = signedOrder.makerTokenAmount.minus(partiallyFilledAmount); remainingMakerTokenAmount = signedOrder.makerTokenAmount.minus(partiallyFilledAmount);
transferrableMakerTokenAmount = remainingMakerTokenAmount.minus(partiallyFilledAmount); transferrableMakerTokenAmount = remainingMakerTokenAmount.minus(partiallyFilledAmount);
calculator = new RemainingFillableCalculator(signedOrder, isMakerTokenZRX, calculator = new RemainingFillableCalculator(
transferrableMakerTokenAmount, transferrableMakerFeeTokenAmount, remainingMakerTokenAmount); signedOrder,
isMakerTokenZRX,
transferrableMakerTokenAmount,
transferrableMakerFeeTokenAmount,
remainingMakerTokenAmount,
);
expect(calculator.computeRemainingMakerFillable()).to.be.bignumber.equal(transferrableMakerTokenAmount); expect(calculator.computeRemainingMakerFillable()).to.be.bignumber.equal(transferrableMakerTokenAmount);
}); });
describe('Order to Fee Ratio is < 1', () => { describe('Order to Fee Ratio is < 1', () => {
beforeEach(async () => { beforeEach(async () => {
[makerAmount, takerAmount, makerFeeAmount] = [ZeroEx.toBaseUnitAmount(new BigNumber(3), decimals), [makerAmount, takerAmount, makerFeeAmount] = [
ZeroEx.toBaseUnitAmount(new BigNumber(3), decimals),
ZeroEx.toBaseUnitAmount(new BigNumber(6), decimals), ZeroEx.toBaseUnitAmount(new BigNumber(6), decimals),
ZeroEx.toBaseUnitAmount(new BigNumber(6), decimals)]; ZeroEx.toBaseUnitAmount(new BigNumber(6), decimals),
];
}); });
it('calculates the correct amount when funds unavailable', () => { it('calculates the correct amount when funds unavailable', () => {
signedOrder = buildSignedOrder(); signedOrder = buildSignedOrder();
remainingMakerTokenAmount = signedOrder.makerTokenAmount; remainingMakerTokenAmount = signedOrder.makerTokenAmount;
const transferredAmount = ZeroEx.toBaseUnitAmount(new BigNumber(2), decimals); const transferredAmount = ZeroEx.toBaseUnitAmount(new BigNumber(2), decimals);
transferrableMakerTokenAmount = remainingMakerTokenAmount.minus(transferredAmount); transferrableMakerTokenAmount = remainingMakerTokenAmount.minus(transferredAmount);
calculator = new RemainingFillableCalculator(signedOrder, isMakerTokenZRX, calculator = new RemainingFillableCalculator(
transferrableMakerTokenAmount, transferrableMakerFeeTokenAmount, signedOrder,
remainingMakerTokenAmount); isMakerTokenZRX,
transferrableMakerTokenAmount,
transferrableMakerFeeTokenAmount,
remainingMakerTokenAmount,
);
expect(calculator.computeRemainingMakerFillable()).to.be.bignumber.equal(transferrableMakerTokenAmount); expect(calculator.computeRemainingMakerFillable()).to.be.bignumber.equal(transferrableMakerTokenAmount);
}); });
}); });
describe('Ratio is not evenly divisble', () => { describe('Ratio is not evenly divisble', () => {
beforeEach(async () => { beforeEach(async () => {
[makerAmount, takerAmount, makerFeeAmount] = [ZeroEx.toBaseUnitAmount(new BigNumber(3), decimals), [makerAmount, takerAmount, makerFeeAmount] = [
ZeroEx.toBaseUnitAmount(new BigNumber(3), decimals),
ZeroEx.toBaseUnitAmount(new BigNumber(7), decimals), ZeroEx.toBaseUnitAmount(new BigNumber(7), decimals),
ZeroEx.toBaseUnitAmount(new BigNumber(7), decimals)]; ZeroEx.toBaseUnitAmount(new BigNumber(7), decimals),
];
}); });
it('calculates the correct amount when funds unavailable', () => { it('calculates the correct amount when funds unavailable', () => {
signedOrder = buildSignedOrder(); signedOrder = buildSignedOrder();
remainingMakerTokenAmount = signedOrder.makerTokenAmount; remainingMakerTokenAmount = signedOrder.makerTokenAmount;
const transferredAmount = ZeroEx.toBaseUnitAmount(new BigNumber(2), decimals); const transferredAmount = ZeroEx.toBaseUnitAmount(new BigNumber(2), decimals);
transferrableMakerTokenAmount = remainingMakerTokenAmount.minus(transferredAmount); transferrableMakerTokenAmount = remainingMakerTokenAmount.minus(transferredAmount);
calculator = new RemainingFillableCalculator(signedOrder, isMakerTokenZRX, calculator = new RemainingFillableCalculator(
transferrableMakerTokenAmount, transferrableMakerFeeTokenAmount, signedOrder,
remainingMakerTokenAmount); isMakerTokenZRX,
transferrableMakerTokenAmount,
transferrableMakerFeeTokenAmount,
remainingMakerTokenAmount,
);
const calculatedFillableAmount = calculator.computeRemainingMakerFillable(); const calculatedFillableAmount = calculator.computeRemainingMakerFillable();
expect(calculatedFillableAmount.lessThanOrEqualTo(transferrableMakerTokenAmount)).to.be.true(); expect(calculatedFillableAmount.lessThanOrEqualTo(transferrableMakerTokenAmount)).to.be.true();
expect(calculatedFillableAmount).to.be.bignumber.greaterThan(new BigNumber(0)); expect(calculatedFillableAmount).to.be.bignumber.greaterThan(new BigNumber(0));
@ -134,15 +171,25 @@ describe('RemainingFillableCalculator', () => {
transferrableMakerTokenAmount = makerAmount.plus(makerFeeAmount); transferrableMakerTokenAmount = makerAmount.plus(makerFeeAmount);
transferrableMakerFeeTokenAmount = transferrableMakerTokenAmount; transferrableMakerFeeTokenAmount = transferrableMakerTokenAmount;
remainingMakerTokenAmount = signedOrder.makerTokenAmount; remainingMakerTokenAmount = signedOrder.makerTokenAmount;
calculator = new RemainingFillableCalculator(signedOrder, isMakerTokenZRX, calculator = new RemainingFillableCalculator(
transferrableMakerTokenAmount, transferrableMakerFeeTokenAmount, remainingMakerTokenAmount); signedOrder,
isMakerTokenZRX,
transferrableMakerTokenAmount,
transferrableMakerFeeTokenAmount,
remainingMakerTokenAmount,
);
expect(calculator.computeRemainingMakerFillable()).to.be.bignumber.equal(remainingMakerTokenAmount); expect(calculator.computeRemainingMakerFillable()).to.be.bignumber.equal(remainingMakerTokenAmount);
}); });
it('calculates the correct amount when partially filled and funds available', () => { it('calculates the correct amount when partially filled and funds available', () => {
signedOrder = buildSignedOrder(); signedOrder = buildSignedOrder();
remainingMakerTokenAmount = ZeroEx.toBaseUnitAmount(new BigNumber(1), decimals); remainingMakerTokenAmount = ZeroEx.toBaseUnitAmount(new BigNumber(1), decimals);
calculator = new RemainingFillableCalculator(signedOrder, isMakerTokenZRX, calculator = new RemainingFillableCalculator(
transferrableMakerTokenAmount, transferrableMakerFeeTokenAmount, remainingMakerTokenAmount); signedOrder,
isMakerTokenZRX,
transferrableMakerTokenAmount,
transferrableMakerFeeTokenAmount,
remainingMakerTokenAmount,
);
expect(calculator.computeRemainingMakerFillable()).to.be.bignumber.equal(remainingMakerTokenAmount); expect(calculator.computeRemainingMakerFillable()).to.be.bignumber.equal(remainingMakerTokenAmount);
}); });
it('calculates the amount to be 0 when all fee funds are transferred', () => { it('calculates the amount to be 0 when all fee funds are transferred', () => {
@ -150,8 +197,13 @@ describe('RemainingFillableCalculator', () => {
transferrableMakerTokenAmount = zero; transferrableMakerTokenAmount = zero;
transferrableMakerFeeTokenAmount = zero; transferrableMakerFeeTokenAmount = zero;
remainingMakerTokenAmount = signedOrder.makerTokenAmount; remainingMakerTokenAmount = signedOrder.makerTokenAmount;
calculator = new RemainingFillableCalculator(signedOrder, isMakerTokenZRX, calculator = new RemainingFillableCalculator(
transferrableMakerTokenAmount, transferrableMakerFeeTokenAmount, remainingMakerTokenAmount); signedOrder,
isMakerTokenZRX,
transferrableMakerTokenAmount,
transferrableMakerFeeTokenAmount,
remainingMakerTokenAmount,
);
expect(calculator.computeRemainingMakerFillable()).to.be.bignumber.equal(zero); expect(calculator.computeRemainingMakerFillable()).to.be.bignumber.equal(zero);
}); });
it('calculates the correct amount when balance is less than remaining fillable', () => { it('calculates the correct amount when balance is less than remaining fillable', () => {
@ -163,8 +215,13 @@ describe('RemainingFillableCalculator', () => {
const orderToFeeRatio = signedOrder.makerTokenAmount.dividedToIntegerBy(signedOrder.makerFee); const orderToFeeRatio = signedOrder.makerTokenAmount.dividedToIntegerBy(signedOrder.makerFee);
const expectedFillableAmount = new BigNumber(450980); const expectedFillableAmount = new BigNumber(450980);
calculator = new RemainingFillableCalculator(signedOrder, isMakerTokenZRX, calculator = new RemainingFillableCalculator(
transferrableMakerTokenAmount, transferrableMakerFeeTokenAmount, remainingMakerTokenAmount); signedOrder,
isMakerTokenZRX,
transferrableMakerTokenAmount,
transferrableMakerFeeTokenAmount,
remainingMakerTokenAmount,
);
const calculatedFillableAmount = calculator.computeRemainingMakerFillable(); const calculatedFillableAmount = calculator.computeRemainingMakerFillable();
const numberOfFillsInRatio = calculatedFillableAmount.dividedToIntegerBy(orderToFeeRatio); const numberOfFillsInRatio = calculatedFillableAmount.dividedToIntegerBy(orderToFeeRatio);
const calculatedFillableAmountPlusFees = calculatedFillableAmount.plus(numberOfFillsInRatio); const calculatedFillableAmountPlusFees = calculatedFillableAmount.plus(numberOfFillsInRatio);

View File

@ -6,13 +6,7 @@ import 'mocha';
import * as Sinon from 'sinon'; import * as Sinon from 'sinon';
import * as Web3 from 'web3'; import * as Web3 from 'web3';
import { import { ApprovalContractEventArgs, DecodedLogEvent, Token, TokenEvents, ZeroEx } from '../src';
ApprovalContractEventArgs,
DecodedLogEvent,
Token,
TokenEvents,
ZeroEx,
} from '../src';
import { DoneCallback } from '../src/types'; import { DoneCallback } from '../src/types';
import { chaiSetup } from './utils/chai_setup'; import { chaiSetup } from './utils/chai_setup';
@ -72,12 +66,8 @@ describe('SubscriptionTest', () => {
done(); done();
}, },
); );
stubs = [ stubs = [Sinon.stub((zeroEx as any)._web3Wrapper, 'getBlockAsync').throws(new Error(errMsg))];
Sinon.stub((zeroEx as any)._web3Wrapper, 'getBlockAsync') zeroEx.token.subscribe(tokenAddress, TokenEvents.Approval, indexFilterValues, callback);
.throws(new Error(errMsg)),
];
zeroEx.token.subscribe(
tokenAddress, TokenEvents.Approval, indexFilterValues, callback);
await zeroEx.token.setAllowanceAsync(tokenAddress, coinbase, addressWithoutFunds, allowanceAmount); await zeroEx.token.setAllowanceAsync(tokenAddress, coinbase, addressWithoutFunds, allowanceAmount);
})().catch(done); })().catch(done);
}); });
@ -91,24 +81,16 @@ describe('SubscriptionTest', () => {
done(); done();
}, },
); );
stubs = [ stubs = [Sinon.stub((zeroEx as any)._web3Wrapper, 'getLogsAsync').throws(new Error(errMsg))];
Sinon.stub((zeroEx as any)._web3Wrapper, 'getLogsAsync') zeroEx.token.subscribe(tokenAddress, TokenEvents.Approval, indexFilterValues, callback);
.throws(new Error(errMsg)),
];
zeroEx.token.subscribe(
tokenAddress, TokenEvents.Approval, indexFilterValues, callback);
await zeroEx.token.setAllowanceAsync(tokenAddress, coinbase, addressWithoutFunds, allowanceAmount); await zeroEx.token.setAllowanceAsync(tokenAddress, coinbase, addressWithoutFunds, allowanceAmount);
})().catch(done); })().catch(done);
}); });
it('Should allow unsubscribeAll to be called successfully after an error', (done: DoneCallback) => { it('Should allow unsubscribeAll to be called successfully after an error', (done: DoneCallback) => {
(async () => { (async () => {
const callback = (err: Error, logEvent: DecodedLogEvent<ApprovalContractEventArgs>) => _.noop; const callback = (err: Error, logEvent: DecodedLogEvent<ApprovalContractEventArgs>) => _.noop;
zeroEx.token.subscribe( zeroEx.token.subscribe(tokenAddress, TokenEvents.Approval, indexFilterValues, callback);
tokenAddress, TokenEvents.Approval, indexFilterValues, callback); stubs = [Sinon.stub((zeroEx as any)._web3Wrapper, 'getBlockAsync').throws(new Error('JSON RPC error'))];
stubs = [
Sinon.stub((zeroEx as any)._web3Wrapper, 'getBlockAsync')
.throws(new Error('JSON RPC error')),
];
zeroEx.token.unsubscribeAll(); zeroEx.token.unsubscribeAll();
done(); done();
})().catch(done); })().catch(done);

View File

@ -74,17 +74,17 @@ describe('TokenWrapper', () => {
it('should fail to transfer tokens if fromAddress has an insufficient balance', async () => { it('should fail to transfer tokens if fromAddress has an insufficient balance', async () => {
const fromAddress = addressWithoutFunds; const fromAddress = addressWithoutFunds;
const toAddress = coinbase; const toAddress = coinbase;
return expect(zeroEx.token.transferAsync( return expect(
token.address, fromAddress, toAddress, transferAmount, zeroEx.token.transferAsync(token.address, fromAddress, toAddress, transferAmount),
)).to.be.rejectedWith(ZeroExError.InsufficientBalanceForTransfer); ).to.be.rejectedWith(ZeroExError.InsufficientBalanceForTransfer);
}); });
it('should throw a CONTRACT_DOES_NOT_EXIST error for a non-existent token contract', async () => { it('should throw a CONTRACT_DOES_NOT_EXIST error for a non-existent token contract', async () => {
const nonExistentTokenAddress = '0x9dd402f14d67e001d8efbe6583e51bf9706aa065'; const nonExistentTokenAddress = '0x9dd402f14d67e001d8efbe6583e51bf9706aa065';
const fromAddress = coinbase; const fromAddress = coinbase;
const toAddress = coinbase; const toAddress = coinbase;
return expect(zeroEx.token.transferAsync( return expect(
nonExistentTokenAddress, fromAddress, toAddress, transferAmount, zeroEx.token.transferAsync(nonExistentTokenAddress, fromAddress, toAddress, transferAmount),
)).to.be.rejectedWith(ZeroExError.TokenContractDoesNotExist); ).to.be.rejectedWith(ZeroExError.TokenContractDoesNotExist);
}); });
}); });
describe('#transferFromAsync', () => { describe('#transferFromAsync', () => {
@ -103,24 +103,22 @@ describe('TokenWrapper', () => {
const fromAddressBalance = await zeroEx.token.getBalanceAsync(token.address, fromAddress); const fromAddressBalance = await zeroEx.token.getBalanceAsync(token.address, fromAddress);
expect(fromAddressBalance).to.be.bignumber.greaterThan(transferAmount); expect(fromAddressBalance).to.be.bignumber.greaterThan(transferAmount);
const fromAddressAllowance = await zeroEx.token.getAllowanceAsync(token.address, fromAddress, const fromAddressAllowance = await zeroEx.token.getAllowanceAsync(token.address, fromAddress, toAddress);
toAddress);
expect(fromAddressAllowance).to.be.bignumber.equal(0); expect(fromAddressAllowance).to.be.bignumber.equal(0);
return expect(zeroEx.token.transferFromAsync( return expect(
token.address, fromAddress, toAddress, senderAddress, transferAmount, zeroEx.token.transferFromAsync(token.address, fromAddress, toAddress, senderAddress, transferAmount),
)).to.be.rejectedWith(ZeroExError.InsufficientAllowanceForTransfer); ).to.be.rejectedWith(ZeroExError.InsufficientAllowanceForTransfer);
}); });
it('[regression] should fail to transfer tokens if set allowance for toAddress instead of senderAddress', it('[regression] should fail to transfer tokens if set allowance for toAddress instead of senderAddress', async () => {
async () => {
const fromAddress = coinbase; const fromAddress = coinbase;
const transferAmount = new BigNumber(42); const transferAmount = new BigNumber(42);
await zeroEx.token.setAllowanceAsync(token.address, fromAddress, toAddress, transferAmount); await zeroEx.token.setAllowanceAsync(token.address, fromAddress, toAddress, transferAmount);
return expect(zeroEx.token.transferFromAsync( return expect(
token.address, fromAddress, toAddress, senderAddress, transferAmount, zeroEx.token.transferFromAsync(token.address, fromAddress, toAddress, senderAddress, transferAmount),
)).to.be.rejectedWith(ZeroExError.InsufficientAllowanceForTransfer); ).to.be.rejectedWith(ZeroExError.InsufficientAllowanceForTransfer);
}); });
it('should fail to transfer tokens if fromAddress has insufficient balance', async () => { it('should fail to transfer tokens if fromAddress has insufficient balance', async () => {
const fromAddress = addressWithoutFunds; const fromAddress = addressWithoutFunds;
@ -130,13 +128,16 @@ describe('TokenWrapper', () => {
expect(fromAddressBalance).to.be.bignumber.equal(0); expect(fromAddressBalance).to.be.bignumber.equal(0);
await zeroEx.token.setAllowanceAsync(token.address, fromAddress, senderAddress, transferAmount); await zeroEx.token.setAllowanceAsync(token.address, fromAddress, senderAddress, transferAmount);
const fromAddressAllowance = await zeroEx.token.getAllowanceAsync(token.address, fromAddress, const fromAddressAllowance = await zeroEx.token.getAllowanceAsync(
senderAddress); token.address,
fromAddress,
senderAddress,
);
expect(fromAddressAllowance).to.be.bignumber.equal(transferAmount); expect(fromAddressAllowance).to.be.bignumber.equal(transferAmount);
return expect(zeroEx.token.transferFromAsync( return expect(
token.address, fromAddress, toAddress, senderAddress, transferAmount, zeroEx.token.transferFromAsync(token.address, fromAddress, toAddress, senderAddress, transferAmount),
)).to.be.rejectedWith(ZeroExError.InsufficientBalanceForTransfer); ).to.be.rejectedWith(ZeroExError.InsufficientBalanceForTransfer);
}); });
it('should successfully transfer tokens', async () => { it('should successfully transfer tokens', async () => {
const fromAddress = coinbase; const fromAddress = coinbase;
@ -147,17 +148,22 @@ describe('TokenWrapper', () => {
const transferAmount = new BigNumber(42); const transferAmount = new BigNumber(42);
await zeroEx.token.setAllowanceAsync(token.address, fromAddress, senderAddress, transferAmount); await zeroEx.token.setAllowanceAsync(token.address, fromAddress, senderAddress, transferAmount);
await zeroEx.token.transferFromAsync(token.address, fromAddress, toAddress, senderAddress, await zeroEx.token.transferFromAsync(token.address, fromAddress, toAddress, senderAddress, transferAmount);
transferAmount);
const postBalance = await zeroEx.token.getBalanceAsync(token.address, toAddress); const postBalance = await zeroEx.token.getBalanceAsync(token.address, toAddress);
return expect(postBalance).to.be.bignumber.equal(transferAmount); return expect(postBalance).to.be.bignumber.equal(transferAmount);
}); });
it('should throw a CONTRACT_DOES_NOT_EXIST error for a non-existent token contract', async () => { it('should throw a CONTRACT_DOES_NOT_EXIST error for a non-existent token contract', async () => {
const fromAddress = coinbase; const fromAddress = coinbase;
const nonExistentTokenAddress = '0x9dd402f14d67e001d8efbe6583e51bf9706aa065'; const nonExistentTokenAddress = '0x9dd402f14d67e001d8efbe6583e51bf9706aa065';
return expect(zeroEx.token.transferFromAsync( return expect(
nonExistentTokenAddress, fromAddress, toAddress, senderAddress, new BigNumber(42), zeroEx.token.transferFromAsync(
)).to.be.rejectedWith(ZeroExError.TokenContractDoesNotExist); nonExistentTokenAddress,
fromAddress,
toAddress,
senderAddress,
new BigNumber(42),
),
).to.be.rejectedWith(ZeroExError.TokenContractDoesNotExist);
}); });
}); });
describe('#getBalanceAsync', () => { describe('#getBalanceAsync', () => {
@ -172,8 +178,9 @@ describe('TokenWrapper', () => {
it('should throw a CONTRACT_DOES_NOT_EXIST error for a non-existent token contract', async () => { it('should throw a CONTRACT_DOES_NOT_EXIST error for a non-existent token contract', async () => {
const nonExistentTokenAddress = '0x9dd402f14d67e001d8efbe6583e51bf9706aa065'; const nonExistentTokenAddress = '0x9dd402f14d67e001d8efbe6583e51bf9706aa065';
const ownerAddress = coinbase; const ownerAddress = coinbase;
return expect(zeroEx.token.getBalanceAsync(nonExistentTokenAddress, ownerAddress)) return expect(zeroEx.token.getBalanceAsync(nonExistentTokenAddress, ownerAddress)).to.be.rejectedWith(
.to.be.rejectedWith(ZeroExError.TokenContractDoesNotExist); ZeroExError.TokenContractDoesNotExist,
);
}); });
it('should return a balance of 0 for a non-existent owner address', async () => { it('should return a balance of 0 for a non-existent owner address', async () => {
const token = tokens[0]; const token = tokens[0];
@ -200,13 +207,16 @@ describe('TokenWrapper', () => {
}); });
}); });
describe('#setAllowanceAsync', () => { describe('#setAllowanceAsync', () => {
it('should set the spender\'s allowance', async () => { it("should set the spender's allowance", async () => {
const token = tokens[0]; const token = tokens[0];
const ownerAddress = coinbase; const ownerAddress = coinbase;
const spenderAddress = addressWithoutFunds; const spenderAddress = addressWithoutFunds;
const allowanceBeforeSet = await zeroEx.token.getAllowanceAsync(token.address, ownerAddress, const allowanceBeforeSet = await zeroEx.token.getAllowanceAsync(
spenderAddress); token.address,
ownerAddress,
spenderAddress,
);
const expectedAllowanceBeforeAllowanceSet = new BigNumber(0); const expectedAllowanceBeforeAllowanceSet = new BigNumber(0);
expect(allowanceBeforeSet).to.be.bignumber.equal(expectedAllowanceBeforeAllowanceSet); expect(allowanceBeforeSet).to.be.bignumber.equal(expectedAllowanceBeforeAllowanceSet);
@ -219,7 +229,7 @@ describe('TokenWrapper', () => {
}); });
}); });
describe('#setUnlimitedAllowanceAsync', () => { describe('#setUnlimitedAllowanceAsync', () => {
it('should set the unlimited spender\'s allowance', async () => { it("should set the unlimited spender's allowance", async () => {
const token = tokens[0]; const token = tokens[0];
const ownerAddress = coinbase; const ownerAddress = coinbase;
const spenderAddress = addressWithoutFunds; const spenderAddress = addressWithoutFunds;
@ -241,10 +251,18 @@ describe('TokenWrapper', () => {
); );
await zeroEx.token.transferFromAsync( await zeroEx.token.transferFromAsync(
zrx.address, coinbase, userWithNormalAllowance, userWithNormalAllowance, transferAmount, zrx.address,
coinbase,
userWithNormalAllowance,
userWithNormalAllowance,
transferAmount,
); );
await zeroEx.token.transferFromAsync( await zeroEx.token.transferFromAsync(
zrx.address, coinbase, userWithUnlimitedAllowance, userWithUnlimitedAllowance, transferAmount, zrx.address,
coinbase,
userWithUnlimitedAllowance,
userWithUnlimitedAllowance,
transferAmount,
); );
const finalBalanceWithNormalAllowance = await web3Wrapper.getBalanceInWeiAsync(userWithNormalAllowance); const finalBalanceWithNormalAllowance = await web3Wrapper.getBalanceInWeiAsync(userWithNormalAllowance);
@ -300,7 +318,9 @@ describe('TokenWrapper', () => {
await zeroEx.token.setAllowanceAsync(token.address, ownerAddress, spenderAddress, amountInBaseUnits); await zeroEx.token.setAllowanceAsync(token.address, ownerAddress, spenderAddress, amountInBaseUnits);
const allowance = await zeroExWithoutAccounts.token.getAllowanceAsync( const allowance = await zeroExWithoutAccounts.token.getAllowanceAsync(
token.address, ownerAddress, spenderAddress, token.address,
ownerAddress,
spenderAddress,
); );
const expectedAllowance = amountInBaseUnits; const expectedAllowance = amountInBaseUnits;
return expect(allowance).to.be.bignumber.equal(expectedAllowance); return expect(allowance).to.be.bignumber.equal(expectedAllowance);
@ -378,8 +398,7 @@ describe('TokenWrapper', () => {
expect(args._value).to.be.bignumber.equal(transferAmount); expect(args._value).to.be.bignumber.equal(transferAmount);
done(); done();
}; };
zeroEx.token.subscribe( zeroEx.token.subscribe(tokenAddress, TokenEvents.Transfer, indexFilterValues, callback);
tokenAddress, TokenEvents.Transfer, indexFilterValues, callback);
await zeroEx.token.transferAsync(tokenAddress, coinbase, addressWithoutFunds, transferAmount); await zeroEx.token.transferAsync(tokenAddress, coinbase, addressWithoutFunds, transferAmount);
})().catch(done); })().catch(done);
}); });
@ -394,8 +413,7 @@ describe('TokenWrapper', () => {
expect(args._value).to.be.bignumber.equal(allowanceAmount); expect(args._value).to.be.bignumber.equal(allowanceAmount);
done(); done();
}; };
zeroEx.token.subscribe( zeroEx.token.subscribe(tokenAddress, TokenEvents.Approval, indexFilterValues, callback);
tokenAddress, TokenEvents.Approval, indexFilterValues, callback);
await zeroEx.token.setAllowanceAsync(tokenAddress, coinbase, addressWithoutFunds, allowanceAmount); await zeroEx.token.setAllowanceAsync(tokenAddress, coinbase, addressWithoutFunds, allowanceAmount);
})().catch(done); })().catch(done);
}); });
@ -404,17 +422,13 @@ describe('TokenWrapper', () => {
const callbackNeverToBeCalled = (err: Error, logEvent: DecodedLogEvent<ApprovalContractEventArgs>) => { const callbackNeverToBeCalled = (err: Error, logEvent: DecodedLogEvent<ApprovalContractEventArgs>) => {
done(new Error('Expected this subscription to have been cancelled')); done(new Error('Expected this subscription to have been cancelled'));
}; };
zeroEx.token.subscribe( zeroEx.token.subscribe(tokenAddress, TokenEvents.Transfer, indexFilterValues, callbackNeverToBeCalled);
tokenAddress, TokenEvents.Transfer, indexFilterValues, callbackNeverToBeCalled,
);
const callbackToBeCalled = (err: Error, logEvent: DecodedLogEvent<ApprovalContractEventArgs>) => { const callbackToBeCalled = (err: Error, logEvent: DecodedLogEvent<ApprovalContractEventArgs>) => {
done(); done();
}; };
const newProvider = web3Factory.getRpcProvider(); const newProvider = web3Factory.getRpcProvider();
zeroEx.setProvider(newProvider, constants.TESTRPC_NETWORK_ID); zeroEx.setProvider(newProvider, constants.TESTRPC_NETWORK_ID);
zeroEx.token.subscribe( zeroEx.token.subscribe(tokenAddress, TokenEvents.Transfer, indexFilterValues, callbackToBeCalled);
tokenAddress, TokenEvents.Transfer, indexFilterValues, callbackToBeCalled,
);
await zeroEx.token.transferAsync(tokenAddress, coinbase, addressWithoutFunds, transferAmount); await zeroEx.token.transferAsync(tokenAddress, coinbase, addressWithoutFunds, transferAmount);
})().catch(done); })().catch(done);
}); });
@ -424,7 +438,11 @@ describe('TokenWrapper', () => {
done(new Error('Expected this subscription to have been cancelled')); done(new Error('Expected this subscription to have been cancelled'));
}; };
const subscriptionToken = zeroEx.token.subscribe( const subscriptionToken = zeroEx.token.subscribe(
tokenAddress, TokenEvents.Transfer, indexFilterValues, callbackNeverToBeCalled); tokenAddress,
TokenEvents.Transfer,
indexFilterValues,
callbackNeverToBeCalled,
);
zeroEx.token.unsubscribe(subscriptionToken); zeroEx.token.unsubscribe(subscriptionToken);
await zeroEx.token.transferAsync(tokenAddress, coinbase, addressWithoutFunds, transferAmount); await zeroEx.token.transferAsync(tokenAddress, coinbase, addressWithoutFunds, transferAmount);
done(); done();
@ -450,7 +468,10 @@ describe('TokenWrapper', () => {
const eventName = TokenEvents.Approval; const eventName = TokenEvents.Approval;
const indexFilterValues = {}; const indexFilterValues = {};
const logs = await zeroEx.token.getLogsAsync<ApprovalContractEventArgs>( const logs = await zeroEx.token.getLogsAsync<ApprovalContractEventArgs>(
tokenAddress, eventName, blockRange, indexFilterValues, tokenAddress,
eventName,
blockRange,
indexFilterValues,
); );
expect(logs).to.have.length(1); expect(logs).to.have.length(1);
const args = logs[0].args; const args = logs[0].args;
@ -465,7 +486,10 @@ describe('TokenWrapper', () => {
const differentEventName = TokenEvents.Transfer; const differentEventName = TokenEvents.Transfer;
const indexFilterValues = {}; const indexFilterValues = {};
const logs = await zeroEx.token.getLogsAsync( const logs = await zeroEx.token.getLogsAsync(
tokenAddress, differentEventName, blockRange, indexFilterValues, tokenAddress,
differentEventName,
blockRange,
indexFilterValues,
); );
expect(logs).to.have.length(0); expect(logs).to.have.length(0);
}); });
@ -479,7 +503,10 @@ describe('TokenWrapper', () => {
_owner: coinbase, _owner: coinbase,
}; };
const logs = await zeroEx.token.getLogsAsync<ApprovalContractEventArgs>( const logs = await zeroEx.token.getLogsAsync<ApprovalContractEventArgs>(
tokenAddress, eventName, blockRange, indexFilterValues, tokenAddress,
eventName,
blockRange,
indexFilterValues,
); );
expect(logs).to.have.length(1); expect(logs).to.have.length(1);
const args = logs[0].args; const args = logs[0].args;
@ -487,3 +514,4 @@ describe('TokenWrapper', () => {
}); });
}); });
}); });
// tslint:disable:max-file-line-count

View File

@ -17,8 +17,13 @@ export class FillScenarios {
private _coinbase: string; private _coinbase: string;
private _zrxTokenAddress: string; private _zrxTokenAddress: string;
private _exchangeContractAddress: string; private _exchangeContractAddress: string;
constructor(zeroEx: ZeroEx, userAddresses: string[], constructor(
tokens: Token[], zrxTokenAddress: string, exchangeContractAddress: string) { zeroEx: ZeroEx,
userAddresses: string[],
tokens: Token[],
zrxTokenAddress: string,
exchangeContractAddress: string,
) {
this._zeroEx = zeroEx; this._zeroEx = zeroEx;
this._userAddresses = userAddresses; this._userAddresses = userAddresses;
this._tokens = tokens; this._tokens = tokens;
@ -31,7 +36,8 @@ export class FillScenarios {
for (const token of this._tokens) { for (const token of this._tokens) {
if (token.symbol !== 'ZRX' && token.symbol !== 'WETH') { if (token.symbol !== 'ZRX' && token.symbol !== 'WETH') {
const contractInstance = web3Wrapper.getContractInstance( const contractInstance = web3Wrapper.getContractInstance(
artifacts.DummyTokenArtifact.abi, token.address, artifacts.DummyTokenArtifact.abi,
token.address,
); );
const defaults = {}; const defaults = {};
const dummyToken = new DummyTokenContract(contractInstance, defaults); const dummyToken = new DummyTokenContract(contractInstance, defaults);
@ -43,61 +49,110 @@ export class FillScenarios {
} }
} }
} }
public async createFillableSignedOrderAsync(makerTokenAddress: string, takerTokenAddress: string, public async createFillableSignedOrderAsync(
makerAddress: string, takerAddress: string, makerTokenAddress: string,
takerTokenAddress: string,
makerAddress: string,
takerAddress: string,
fillableAmount: BigNumber, fillableAmount: BigNumber,
expirationUnixTimestampSec?: BigNumber): expirationUnixTimestampSec?: BigNumber,
Promise<SignedOrder> { ): Promise<SignedOrder> {
return this.createAsymmetricFillableSignedOrderAsync( return this.createAsymmetricFillableSignedOrderAsync(
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, makerTokenAddress,
fillableAmount, fillableAmount, expirationUnixTimestampSec, takerTokenAddress,
makerAddress,
takerAddress,
fillableAmount,
fillableAmount,
expirationUnixTimestampSec,
); );
} }
public async createFillableSignedOrderWithFeesAsync( public async createFillableSignedOrderWithFeesAsync(
makerTokenAddress: string, takerTokenAddress: string, makerTokenAddress: string,
makerFee: BigNumber, takerFee: BigNumber, takerTokenAddress: string,
makerAddress: string, takerAddress: string, makerFee: BigNumber,
takerFee: BigNumber,
makerAddress: string,
takerAddress: string,
fillableAmount: BigNumber, fillableAmount: BigNumber,
feeRecepient: string, expirationUnixTimestampSec?: BigNumber, feeRecepient: string,
expirationUnixTimestampSec?: BigNumber,
): Promise<SignedOrder> { ): Promise<SignedOrder> {
return this._createAsymmetricFillableSignedOrderWithFeesAsync( return this._createAsymmetricFillableSignedOrderWithFeesAsync(
makerTokenAddress, takerTokenAddress, makerFee, takerFee, makerAddress, takerAddress, makerTokenAddress,
fillableAmount, fillableAmount, feeRecepient, expirationUnixTimestampSec, takerTokenAddress,
makerFee,
takerFee,
makerAddress,
takerAddress,
fillableAmount,
fillableAmount,
feeRecepient,
expirationUnixTimestampSec,
); );
} }
public async createAsymmetricFillableSignedOrderAsync( public async createAsymmetricFillableSignedOrderAsync(
makerTokenAddress: string, takerTokenAddress: string, makerAddress: string, takerAddress: string, makerTokenAddress: string,
makerFillableAmount: BigNumber, takerFillableAmount: BigNumber, takerTokenAddress: string,
expirationUnixTimestampSec?: BigNumber): Promise<SignedOrder> { makerAddress: string,
takerAddress: string,
makerFillableAmount: BigNumber,
takerFillableAmount: BigNumber,
expirationUnixTimestampSec?: BigNumber,
): Promise<SignedOrder> {
const makerFee = new BigNumber(0); const makerFee = new BigNumber(0);
const takerFee = new BigNumber(0); const takerFee = new BigNumber(0);
const feeRecepient = constants.NULL_ADDRESS; const feeRecepient = constants.NULL_ADDRESS;
return this._createAsymmetricFillableSignedOrderWithFeesAsync( return this._createAsymmetricFillableSignedOrderWithFeesAsync(
makerTokenAddress, takerTokenAddress, makerFee, takerFee, makerAddress, takerAddress, makerTokenAddress,
makerFillableAmount, takerFillableAmount, feeRecepient, expirationUnixTimestampSec, takerTokenAddress,
makerFee,
takerFee,
makerAddress,
takerAddress,
makerFillableAmount,
takerFillableAmount,
feeRecepient,
expirationUnixTimestampSec,
); );
} }
public async createPartiallyFilledSignedOrderAsync(makerTokenAddress: string, takerTokenAddress: string, public async createPartiallyFilledSignedOrderAsync(
takerAddress: string, fillableAmount: BigNumber, makerTokenAddress: string,
partialFillAmount: BigNumber) { takerTokenAddress: string,
takerAddress: string,
fillableAmount: BigNumber,
partialFillAmount: BigNumber,
) {
const [makerAddress] = this._userAddresses; const [makerAddress] = this._userAddresses;
const signedOrder = await this.createAsymmetricFillableSignedOrderAsync( const signedOrder = await this.createAsymmetricFillableSignedOrderAsync(
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, makerTokenAddress,
fillableAmount, fillableAmount, takerTokenAddress,
makerAddress,
takerAddress,
fillableAmount,
fillableAmount,
); );
const shouldThrowOnInsufficientBalanceOrAllowance = false; const shouldThrowOnInsufficientBalanceOrAllowance = false;
await this._zeroEx.exchange.fillOrderAsync( await this._zeroEx.exchange.fillOrderAsync(
signedOrder, partialFillAmount, shouldThrowOnInsufficientBalanceOrAllowance, takerAddress, signedOrder,
partialFillAmount,
shouldThrowOnInsufficientBalanceOrAllowance,
takerAddress,
); );
return signedOrder; return signedOrder;
} }
private async _createAsymmetricFillableSignedOrderWithFeesAsync( private async _createAsymmetricFillableSignedOrderWithFeesAsync(
makerTokenAddress: string, takerTokenAddress: string, makerTokenAddress: string,
makerFee: BigNumber, takerFee: BigNumber, takerTokenAddress: string,
makerAddress: string, takerAddress: string, makerFee: BigNumber,
makerFillableAmount: BigNumber, takerFillableAmount: BigNumber, takerFee: BigNumber,
feeRecepient: string, expirationUnixTimestampSec?: BigNumber): Promise<SignedOrder> { makerAddress: string,
takerAddress: string,
makerFillableAmount: BigNumber,
takerFillableAmount: BigNumber,
feeRecepient: string,
expirationUnixTimestampSec?: BigNumber,
): Promise<SignedOrder> {
await Promise.all([ await Promise.all([
this._increaseBalanceAndAllowanceAsync(makerTokenAddress, makerAddress, makerFillableAmount), this._increaseBalanceAndAllowanceAsync(makerTokenAddress, makerAddress, makerFillableAmount),
this._increaseBalanceAndAllowanceAsync(takerTokenAddress, takerAddress, takerFillableAmount), this._increaseBalanceAndAllowanceAsync(takerTokenAddress, takerAddress, takerFillableAmount),
@ -107,14 +162,27 @@ export class FillScenarios {
this._increaseBalanceAndAllowanceAsync(this._zrxTokenAddress, takerAddress, takerFee), this._increaseBalanceAndAllowanceAsync(this._zrxTokenAddress, takerAddress, takerFee),
]); ]);
const signedOrder = await orderFactory.createSignedOrderAsync(this._zeroEx, const signedOrder = await orderFactory.createSignedOrderAsync(
makerAddress, takerAddress, makerFee, takerFee, this._zeroEx,
makerFillableAmount, makerTokenAddress, takerFillableAmount, takerTokenAddress, makerAddress,
this._exchangeContractAddress, feeRecepient, expirationUnixTimestampSec); takerAddress,
makerFee,
takerFee,
makerFillableAmount,
makerTokenAddress,
takerFillableAmount,
takerTokenAddress,
this._exchangeContractAddress,
feeRecepient,
expirationUnixTimestampSec,
);
return signedOrder; return signedOrder;
} }
private async _increaseBalanceAndAllowanceAsync( private async _increaseBalanceAndAllowanceAsync(
tokenAddress: string, address: string, amount: BigNumber): Promise<void> { tokenAddress: string,
address: string,
amount: BigNumber,
): Promise<void> {
if (amount.isZero() || address === ZeroEx.NULL_ADDRESS) { if (amount.isZero() || address === ZeroEx.NULL_ADDRESS) {
return; // noop return; // noop
} }
@ -123,16 +191,12 @@ export class FillScenarios {
this._increaseAllowanceAsync(tokenAddress, address, amount), this._increaseAllowanceAsync(tokenAddress, address, amount),
]); ]);
} }
private async _increaseBalanceAsync( private async _increaseBalanceAsync(tokenAddress: string, address: string, amount: BigNumber): Promise<void> {
tokenAddress: string, address: string, amount: BigNumber): Promise<void> {
await this._zeroEx.token.transferAsync(tokenAddress, this._coinbase, address, amount); await this._zeroEx.token.transferAsync(tokenAddress, this._coinbase, address, amount);
} }
private async _increaseAllowanceAsync( private async _increaseAllowanceAsync(tokenAddress: string, address: string, amount: BigNumber): Promise<void> {
tokenAddress: string, address: string, amount: BigNumber): Promise<void> {
const oldMakerAllowance = await this._zeroEx.token.getProxyAllowanceAsync(tokenAddress, address); const oldMakerAllowance = await this._zeroEx.token.getProxyAllowanceAsync(tokenAddress, address);
const newMakerAllowance = oldMakerAllowance.plus(amount); const newMakerAllowance = oldMakerAllowance.plus(amount);
await this._zeroEx.token.setProxyAllowanceAsync( await this._zeroEx.token.setProxyAllowanceAsync(tokenAddress, address, newMakerAllowance);
tokenAddress, address, newMakerAllowance,
);
} }
} }

View File

@ -16,11 +16,12 @@ export const orderFactory = {
takerTokenAddress: string, takerTokenAddress: string,
exchangeContractAddress: string, exchangeContractAddress: string,
feeRecipient: string, feeRecipient: string,
expirationUnixTimestampSecIfExists?: BigNumber): Promise<SignedOrder> { expirationUnixTimestampSecIfExists?: BigNumber,
): Promise<SignedOrder> {
const defaultExpirationUnixTimestampSec = new BigNumber(2524604400); // Close to infinite const defaultExpirationUnixTimestampSec = new BigNumber(2524604400); // Close to infinite
const expirationUnixTimestampSec = _.isUndefined(expirationUnixTimestampSecIfExists) ? const expirationUnixTimestampSec = _.isUndefined(expirationUnixTimestampSecIfExists)
defaultExpirationUnixTimestampSec : ? defaultExpirationUnixTimestampSec
expirationUnixTimestampSecIfExists; : expirationUnixTimestampSecIfExists;
const order = { const order = {
maker, maker,
taker, taker,

View File

@ -31,9 +31,11 @@ export const web3Factory = {
provider.addProvider(new EmptyWalletSubprovider()); provider.addProvider(new EmptyWalletSubprovider());
} }
provider.addProvider(new FakeGasEstimateSubprovider(constants.GAS_ESTIMATE)); provider.addProvider(new FakeGasEstimateSubprovider(constants.GAS_ESTIMATE));
provider.addProvider(new RpcSubprovider({ provider.addProvider(
new RpcSubprovider({
rpcUrl: constants.RPC_URL, rpcUrl: constants.RPC_URL,
})); }),
);
provider.start(); provider.start();
return provider; return provider;
}, },

View File

@ -32,8 +32,7 @@ const args = yargs
describe: 'Folder where to put the output files', describe: 'Folder where to put the output files',
type: 'string', type: 'string',
demand: true, demand: true,
}) }).argv;
.argv;
function writeOutputFile(name: string, renderedTsCode: string): void { function writeOutputFile(name: string, renderedTsCode: string): void {
const fileName = toSnakeCase(name); const fileName = toSnakeCase(name);
@ -66,9 +65,9 @@ for (const abiFileName of abiFileNames) {
const namedContent = utils.getNamedContent(abiFileName); const namedContent = utils.getNamedContent(abiFileName);
utils.log(`Processing: ${chalk.bold(namedContent.name)}...`); utils.log(`Processing: ${chalk.bold(namedContent.name)}...`);
const parsedContent = JSON.parse(namedContent.content); const parsedContent = JSON.parse(namedContent.content);
const ABI = _.isArray(parsedContent) ? const ABI = _.isArray(parsedContent)
parsedContent : // ABI file ? parsedContent // ABI file
parsedContent.abi; // Truffle contracts file : parsedContent.abi; // Truffle contracts file
if (_.isUndefined(ABI)) { if (_.isUndefined(ABI)) {
utils.log(`${chalk.red(`ABI not found in ${abiFileName}.`)}`); utils.log(`${chalk.red(`ABI not found in ${abiFileName}.`)}`);
utils.log(`Please make sure your ABI file is either an array with ABI entries or an object with the abi key`); utils.log(`Please make sure your ABI file is either an array with ABI entries or an object with the abi key`);

View File

@ -23,7 +23,10 @@ export const utils = {
if (paramKind === ParamKind.Input) { if (paramKind === ParamKind.Input) {
// web3 allows to pass those an non-bignumbers and that's nice // web3 allows to pass those an non-bignumbers and that's nice
// but it always returns stuff as BigNumbers // but it always returns stuff as BigNumbers
solTypeRegexToTsType.unshift({regex: '^u?int(8|16|32)?$', tsType: 'number|BigNumber'}); solTypeRegexToTsType.unshift({
regex: '^u?int(8|16|32)?$',
tsType: 'number|BigNumber',
});
} }
for (const regexAndTxType of solTypeRegexToTsType) { for (const regexAndTxType of solTypeRegexToTsType) {
const { regex, tsType } = regexAndTxType; const { regex, tsType } = regexAndTxType;

View File

@ -1,7 +1,4 @@
import { import { Schema, SchemaValidator } from '@0xproject/json-schemas';
Schema,
SchemaValidator,
} from '@0xproject/json-schemas';
import { addressUtils } from '@0xproject/utils'; import { addressUtils } from '@0xproject/utils';
import BigNumber from 'bignumber.js'; import BigNumber from 'bignumber.js';
import * as _ from 'lodash'; import * as _ from 'lodash';
@ -18,7 +15,8 @@ export const assert = {
assert.isBigNumber(variableName, value); assert.isBigNumber(variableName, value);
const hasDecimals = value.decimalPlaces() !== 0; const hasDecimals = value.decimalPlaces() !== 0;
this.assert( this.assert(
!hasDecimals, `${variableName} should be in baseUnits (no decimals), found value: ${value.toNumber()}`, !hasDecimals,
`${variableName} should be in baseUnits (no decimals), found value: ${value.toNumber()}`,
); );
}, },
isUndefined(value: any, variableName?: string): void { isUndefined(value: any, variableName?: string): void {
@ -31,8 +29,10 @@ export const assert = {
this.assert(_.isFunction(value), this.typeAssertionMessage(variableName, 'function', value)); this.assert(_.isFunction(value), this.typeAssertionMessage(variableName, 'function', value));
}, },
isHexString(variableName: string, value: string): void { isHexString(variableName: string, value: string): void {
this.assert(_.isString(value) && HEX_REGEX.test(value), this.assert(
this.typeAssertionMessage(variableName, 'HexString', value)); _.isString(value) && HEX_REGEX.test(value),
this.typeAssertionMessage(variableName, 'HexString', value),
);
}, },
isETHAddressHex(variableName: string, value: string): void { isETHAddressHex(variableName: string, value: string): void {
this.assert(addressUtils.isAddress(value), this.typeAssertionMessage(variableName, 'ETHAddressHex', value)); this.assert(addressUtils.isAddress(value), this.typeAssertionMessage(variableName, 'ETHAddressHex', value));
@ -41,8 +41,11 @@ export const assert = {
`Checksummed addresses are not supported. Convert ${variableName} to lower case before passing`, `Checksummed addresses are not supported. Convert ${variableName} to lower case before passing`,
); );
}, },
doesBelongToStringEnum(variableName: string, value: string, doesBelongToStringEnum(
stringEnum: any /* There is no base type for every string enum */): void { variableName: string,
value: string,
stringEnum: any /* There is no base type for every string enum */,
): void {
const doesBelongToStringEnum = !_.isUndefined(stringEnum[value]); const doesBelongToStringEnum = !_.isUndefined(stringEnum[value]);
const enumValues = _.keys(stringEnum); const enumValues = _.keys(stringEnum);
const enumValuesAsStrings = _.map(enumValues, enumValue => `'${enumValue}'`); const enumValuesAsStrings = _.map(enumValues, enumValue => `'${enumValue}'`);
@ -62,7 +65,7 @@ export const assert = {
this.assert(_.isBoolean(value), this.typeAssertionMessage(variableName, 'boolean', value)); this.assert(_.isBoolean(value), this.typeAssertionMessage(variableName, 'boolean', value));
}, },
isWeb3Provider(variableName: string, value: any): void { isWeb3Provider(variableName: string, value: any): void {
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): void {

View File

@ -14,75 +14,41 @@ describe('Assertions', () => {
const variableName = 'variable'; const variableName = 'variable';
describe('#isBigNumber', () => { describe('#isBigNumber', () => {
it('should not throw for valid input', () => { it('should not throw for valid input', () => {
const validInputs = [ const validInputs = [new BigNumber(23), new BigNumber('45')];
new BigNumber(23),
new BigNumber('45'),
];
validInputs.forEach(input => expect(assert.isBigNumber.bind(assert, variableName, input)).to.not.throw()); validInputs.forEach(input => expect(assert.isBigNumber.bind(assert, variableName, input)).to.not.throw());
}); });
it('should throw for invalid input', () => { it('should throw for invalid input', () => {
const invalidInputs = [ const invalidInputs = ['test', 42, false, { random: 'test' }, undefined];
'test',
42,
false,
{random: 'test'},
undefined,
];
invalidInputs.forEach(input => expect(assert.isBigNumber.bind(assert, variableName, input)).to.throw()); invalidInputs.forEach(input => expect(assert.isBigNumber.bind(assert, variableName, input)).to.throw());
}); });
}); });
describe('#isUndefined', () => { describe('#isUndefined', () => {
it('should not throw for valid input', () => { it('should not throw for valid input', () => {
const validInputs = [ const validInputs = [undefined];
undefined,
];
validInputs.forEach(input => expect(assert.isUndefined.bind(assert, input, variableName)).to.not.throw()); validInputs.forEach(input => expect(assert.isUndefined.bind(assert, input, variableName)).to.not.throw());
}); });
it('should throw for invalid input', () => { it('should throw for invalid input', () => {
const invalidInputs = [ const invalidInputs = ['test', 42, false, { random: 'test' }];
'test',
42,
false,
{random: 'test'},
];
invalidInputs.forEach(input => expect(assert.isUndefined.bind(assert, input, variableName)).to.throw()); invalidInputs.forEach(input => expect(assert.isUndefined.bind(assert, input, variableName)).to.throw());
}); });
}); });
describe('#isString', () => { describe('#isString', () => {
it('should not throw for valid input', () => { it('should not throw for valid input', () => {
const validInputs = [ const validInputs = ['hello', 'goodbye'];
'hello',
'goodbye',
];
validInputs.forEach(input => expect(assert.isString.bind(assert, variableName, input)).to.not.throw()); validInputs.forEach(input => expect(assert.isString.bind(assert, variableName, input)).to.not.throw());
}); });
it('should throw for invalid input', () => { it('should throw for invalid input', () => {
const invalidInputs = [ const invalidInputs = [42, false, { random: 'test' }, undefined, new BigNumber(45)];
42,
false,
{random: 'test'},
undefined,
new BigNumber(45),
];
invalidInputs.forEach(input => expect(assert.isString.bind(assert, variableName, input)).to.throw()); invalidInputs.forEach(input => expect(assert.isString.bind(assert, variableName, input)).to.throw());
}); });
}); });
describe('#isFunction', () => { describe('#isFunction', () => {
it('should not throw for valid input', () => { it('should not throw for valid input', () => {
const validInputs = [ const validInputs = [BigNumber, assert.isString.bind(this)];
BigNumber,
assert.isString.bind(this),
];
validInputs.forEach(input => expect(assert.isFunction.bind(assert, variableName, input)).to.not.throw()); validInputs.forEach(input => expect(assert.isFunction.bind(assert, variableName, input)).to.not.throw());
}); });
it('should throw for invalid input', () => { it('should throw for invalid input', () => {
const invalidInputs = [ const invalidInputs = [42, false, { random: 'test' }, undefined, new BigNumber(45)];
42,
false,
{random: 'test'},
undefined,
new BigNumber(45),
];
invalidInputs.forEach(input => expect(assert.isFunction.bind(assert, variableName, input)).to.throw()); invalidInputs.forEach(input => expect(assert.isFunction.bind(assert, variableName, input)).to.throw());
}); });
}); });
@ -127,9 +93,7 @@ describe('Assertions', () => {
'0x6FFFd0ae3f7d88c9b4925323f54c6e4b2918c5fd', '0x6FFFd0ae3f7d88c9b4925323f54c6e4b2918c5fd',
'0x6FFFd0ae3f7d88c9b4925323f54c6e4', '0x6FFFd0ae3f7d88c9b4925323f54c6e4',
]; ];
invalidInputs.forEach(input => invalidInputs.forEach(input => expect(assert.isETHAddressHex.bind(assert, variableName, input)).to.throw());
expect(assert.isETHAddressHex.bind(assert, variableName, input)).to.throw(),
);
}); });
}); });
describe('#doesBelongToStringEnum', () => { describe('#doesBelongToStringEnum', () => {
@ -138,22 +102,13 @@ describe('Assertions', () => {
Test2 = 'Test2', Test2 = 'Test2',
} }
it('should not throw for valid input', () => { it('should not throw for valid input', () => {
const validInputs = [ const validInputs = [TestEnums.Test1, TestEnums.Test2];
TestEnums.Test1,
TestEnums.Test2,
];
validInputs.forEach(input => validInputs.forEach(input =>
expect(assert.doesBelongToStringEnum.bind(assert, variableName, input, TestEnums)).to.not.throw(), expect(assert.doesBelongToStringEnum.bind(assert, variableName, input, TestEnums)).to.not.throw(),
); );
}); });
it('should throw for invalid input', () => { it('should throw for invalid input', () => {
const invalidInputs = [ const invalidInputs = [42, false, { random: 'test' }, undefined, new BigNumber(45)];
42,
false,
{random: 'test'},
undefined,
new BigNumber(45),
];
invalidInputs.forEach(input => invalidInputs.forEach(input =>
expect(assert.doesBelongToStringEnum.bind(assert, variableName, input, TestEnums)).to.throw(), expect(assert.doesBelongToStringEnum.bind(assert, variableName, input, TestEnums)).to.throw(),
); );
@ -162,19 +117,13 @@ describe('Assertions', () => {
describe('#hasAtMostOneUniqueValue', () => { describe('#hasAtMostOneUniqueValue', () => {
const errorMsg = 'more than one unique value'; const errorMsg = 'more than one unique value';
it('should not throw for valid input', () => { it('should not throw for valid input', () => {
const validInputs = [ const validInputs = [['hello'], ['goodbye', 'goodbye', 'goodbye']];
['hello'],
['goodbye', 'goodbye', 'goodbye'],
];
validInputs.forEach(input => validInputs.forEach(input =>
expect(assert.hasAtMostOneUniqueValue.bind(assert, input, errorMsg)).to.not.throw(), expect(assert.hasAtMostOneUniqueValue.bind(assert, input, errorMsg)).to.not.throw(),
); );
}); });
it('should throw for invalid input', () => { it('should throw for invalid input', () => {
const invalidInputs = [ const invalidInputs = [['hello', 'goodbye'], ['goodbye', 42, false, false]];
['hello', 'goodbye'],
['goodbye', 42, false, false],
];
invalidInputs.forEach(input => invalidInputs.forEach(input =>
expect(assert.hasAtMostOneUniqueValue.bind(assert, input, errorMsg)).to.throw(), expect(assert.hasAtMostOneUniqueValue.bind(assert, input, errorMsg)).to.throw(),
); );
@ -182,61 +131,34 @@ describe('Assertions', () => {
}); });
describe('#isNumber', () => { describe('#isNumber', () => {
it('should not throw for valid input', () => { it('should not throw for valid input', () => {
const validInputs = [ const validInputs = [42, 0, 21e42];
42,
0,
21e+42,
];
validInputs.forEach(input => expect(assert.isNumber.bind(assert, variableName, input)).to.not.throw()); validInputs.forEach(input => expect(assert.isNumber.bind(assert, variableName, input)).to.not.throw());
}); });
it('should throw for invalid input', () => { it('should throw for invalid input', () => {
const invalidInputs = [ const invalidInputs = [false, { random: 'test' }, undefined, new BigNumber(45)];
false,
{random: 'test'},
undefined,
new BigNumber(45),
];
invalidInputs.forEach(input => expect(assert.isNumber.bind(assert, variableName, input)).to.throw()); invalidInputs.forEach(input => expect(assert.isNumber.bind(assert, variableName, input)).to.throw());
}); });
}); });
describe('#isBoolean', () => { describe('#isBoolean', () => {
it('should not throw for valid input', () => { it('should not throw for valid input', () => {
const validInputs = [ const validInputs = [true, false];
true,
false,
];
validInputs.forEach(input => expect(assert.isBoolean.bind(assert, variableName, input)).to.not.throw()); validInputs.forEach(input => expect(assert.isBoolean.bind(assert, variableName, input)).to.not.throw());
}); });
it('should throw for invalid input', () => { it('should throw for invalid input', () => {
const invalidInputs = [ const invalidInputs = [42, { random: 'test' }, undefined, new BigNumber(45)];
42,
{random: 'test'},
undefined,
new BigNumber(45),
];
invalidInputs.forEach(input => expect(assert.isBoolean.bind(assert, variableName, input)).to.throw()); invalidInputs.forEach(input => expect(assert.isBoolean.bind(assert, variableName, input)).to.throw());
}); });
}); });
describe('#isWeb3Provider', () => { describe('#isWeb3Provider', () => {
it('should not throw for valid input', () => { it('should not throw for valid input', () => {
const validInputs = [ const validInputs = [{ send: () => 45 }, { sendAsync: () => 45 }];
{send: () => 45},
{sendAsync: () => 45},
];
validInputs.forEach(input => validInputs.forEach(input =>
expect(assert.isWeb3Provider.bind(assert, variableName, input)).to.not.throw(), expect(assert.isWeb3Provider.bind(assert, variableName, input)).to.not.throw(),
); );
}); });
it('should throw for invalid input', () => { it('should throw for invalid input', () => {
const invalidInputs = [ const invalidInputs = [42, { random: 'test' }, undefined, new BigNumber(45)];
42, invalidInputs.forEach(input => expect(assert.isWeb3Provider.bind(assert, variableName, input)).to.throw());
{random: 'test'},
undefined,
new BigNumber(45),
];
invalidInputs.forEach(input =>
expect(assert.isWeb3Provider.bind(assert, variableName, input)).to.throw(),
);
}); });
}); });
describe('#doesConformToSchema', () => { describe('#doesConformToSchema', () => {
@ -251,12 +173,7 @@ describe('Assertions', () => {
); );
}); });
it('should throw for invalid input', () => { it('should throw for invalid input', () => {
const invalidInputs = [ const invalidInputs = [42, { random: 'test' }, undefined, new BigNumber(45)];
42,
{random: 'test'},
undefined,
new BigNumber(45),
];
invalidInputs.forEach(input => invalidInputs.forEach(input =>
expect(assert.doesConformToSchema.bind(assert, variableName, input, schema)).to.throw(), expect(assert.doesConformToSchema.bind(assert, variableName, input, schema)).to.throw(),
); );
@ -270,9 +187,7 @@ describe('Assertions', () => {
'https://api.radarrelay.com/0x/v0/', 'https://api.radarrelay.com/0x/v0/',
'https://zeroex.beta.radarrelay.com:8000/0x/v0/', 'https://zeroex.beta.radarrelay.com:8000/0x/v0/',
]; ];
validInputs.forEach(input => validInputs.forEach(input => expect(assert.isHttpUrl.bind(assert, variableName, input)).to.not.throw());
expect(assert.isHttpUrl.bind(assert, variableName, input)).to.not.throw(),
);
}); });
it('should throw for invalid input', () => { it('should throw for invalid input', () => {
const invalidInputs = [ const invalidInputs = [
@ -286,9 +201,7 @@ describe('Assertions', () => {
'user:password@api.example-relayer.net', 'user:password@api.example-relayer.net',
'//api.example-relayer.net', '//api.example-relayer.net',
]; ];
invalidInputs.forEach(input => invalidInputs.forEach(input => expect(assert.isHttpUrl.bind(assert, variableName, input)).to.throw());
expect(assert.isHttpUrl.bind(assert, variableName, input)).to.throw(),
);
}); });
}); });
describe('#isUri', () => { describe('#isUri', () => {
@ -302,9 +215,7 @@ describe('Assertions', () => {
'wss://www.api.example-relayer.net', 'wss://www.api.example-relayer.net',
'user:password@api.example-relayer.net', 'user:password@api.example-relayer.net',
]; ];
validInputs.forEach(input => validInputs.forEach(input => expect(assert.isUri.bind(assert, variableName, input)).to.not.throw());
expect(assert.isUri.bind(assert, variableName, input)).to.not.throw(),
);
}); });
it('should throw for invalid input', () => { it('should throw for invalid input', () => {
const invalidInputs = [ const invalidInputs = [
@ -316,9 +227,7 @@ describe('Assertions', () => {
'api.example-relayer.net', 'api.example-relayer.net',
'//api.example-relayer.net', '//api.example-relayer.net',
]; ];
invalidInputs.forEach(input => invalidInputs.forEach(input => expect(assert.isUri.bind(assert, variableName, input)).to.throw());
expect(assert.isUri.bind(assert, variableName, input)).to.throw(),
);
}); });
}); });
describe('#assert', () => { describe('#assert', () => {
@ -332,8 +241,9 @@ describe('Assertions', () => {
}); });
describe('#typeAssertionMessage', () => { describe('#typeAssertionMessage', () => {
it('should render correct message', () => { it('should render correct message', () => {
expect(assert.typeAssertionMessage('variable', 'string', 'number')) expect(assert.typeAssertionMessage('variable', 'string', 'number')).to.equal(
.to.equal(`Expected variable to be of type string, encountered: number`); `Expected variable to be of type string, encountered: number`,
);
}); });
}); });
}); });

View File

@ -49,8 +49,7 @@ export class HttpClient implements Client {
params: request, params: request,
}; };
const tokenPairs = await this._requestAsync('/token_pairs', HttpRequestType.Get, requestOpts); const tokenPairs = await this._requestAsync('/token_pairs', HttpRequestType.Get, requestOpts);
assert.doesConformToSchema( assert.doesConformToSchema('tokenPairs', tokenPairs, schemas.relayerApiTokenPairsResponseSchema);
'tokenPairs', tokenPairs, schemas.relayerApiTokenPairsResponseSchema);
_.each(tokenPairs, (tokenPair: object) => { _.each(tokenPairs, (tokenPair: object) => {
typeConverters.convertStringsFieldsToBigNumbers(tokenPair, [ typeConverters.convertStringsFieldsToBigNumbers(tokenPair, [
'tokenA.minAmount', 'tokenA.minAmount',
@ -137,8 +136,11 @@ export class HttpClient implements Client {
}; };
await this._requestAsync('/order', HttpRequestType.Post, requestOpts); await this._requestAsync('/order', HttpRequestType.Post, requestOpts);
} }
private async _requestAsync(path: string, requestType: HttpRequestType, private async _requestAsync(
requestOptions?: HttpRequestOptions): Promise<any> { path: string,
requestType: HttpRequestType,
requestOptions?: HttpRequestOptions,
): Promise<any> {
const params = _.get(requestOptions, 'params'); const params = _.get(requestOptions, 'params');
const payload = _.get(requestOptions, 'payload'); const payload = _.get(requestOptions, 'payload');
let query = ''; let query = '';

View File

@ -1,12 +1,6 @@
import { import { relayerOrderBookRequestSchema } from './relayer_orderbook_request_schema';
relayerOrderBookRequestSchema, import { relayerOrdersRequestSchema } from './relayer_orders_request_schema';
} from './relayer_orderbook_request_schema'; import { relayerTokenPairsRequestSchema } from './relayer_token_pairs_request_schema';
import {
relayerOrdersRequestSchema,
} from './relayer_orders_request_schema';
import {
relayerTokenPairsRequestSchema,
} from './relayer_token_pairs_request_schema';
export const schemas = { export const schemas = {
relayerOrderBookRequestSchema, relayerOrderBookRequestSchema,

View File

@ -57,19 +57,24 @@ export interface OrderbookChannelSubscriptionOpts {
} }
export interface OrderbookChannelHandler { export interface OrderbookChannelHandler {
onSnapshot: (channel: OrderbookChannel, subscriptionOpts: OrderbookChannelSubscriptionOpts, onSnapshot: (
snapshot: OrderbookResponse) => void; channel: OrderbookChannel,
onUpdate: (channel: OrderbookChannel, subscriptionOpts: OrderbookChannelSubscriptionOpts, subscriptionOpts: OrderbookChannelSubscriptionOpts,
order: SignedOrder) => void; snapshot: OrderbookResponse,
onError: (channel: OrderbookChannel, subscriptionOpts: OrderbookChannelSubscriptionOpts, ) => void;
err: Error) => void; onUpdate: (
channel: OrderbookChannel,
subscriptionOpts: OrderbookChannelSubscriptionOpts,
order: SignedOrder,
) => void;
onError: (channel: OrderbookChannel, subscriptionOpts: OrderbookChannelSubscriptionOpts, err: Error) => void;
onClose: (channel: OrderbookChannel, subscriptionOpts: OrderbookChannelSubscriptionOpts) => void; onClose: (channel: OrderbookChannel, subscriptionOpts: OrderbookChannelSubscriptionOpts) => void;
} }
export type OrderbookChannelMessage = export type OrderbookChannelMessage =
SnapshotOrderbookChannelMessage | | SnapshotOrderbookChannelMessage
UpdateOrderbookChannelMessage | | UpdateOrderbookChannelMessage
UnknownOrderbookChannelMessage; | UnknownOrderbookChannelMessage;
export enum OrderbookChannelMessageTypes { export enum OrderbookChannelMessageTypes {
Snapshot = 'snapshot', Snapshot = 'snapshot',

View File

@ -2,10 +2,7 @@ import {assert} from '@0xproject/assert';
import { schemas } from '@0xproject/json-schemas'; import { schemas } from '@0xproject/json-schemas';
import * as _ from 'lodash'; import * as _ from 'lodash';
import { import { OrderbookChannelMessage, OrderbookChannelMessageTypes } from '../types';
OrderbookChannelMessage,
OrderbookChannelMessageTypes,
} from '../types';
import { typeConverters } from './type_converters'; import { typeConverters } from './type_converters';
@ -16,13 +13,13 @@ export const orderbookChannelMessageParsers = {
assert.assert(!_.isUndefined(type), `Message is missing a type parameter: ${utf8Data}`); assert.assert(!_.isUndefined(type), `Message is missing a type parameter: ${utf8Data}`);
assert.isString('type', type); assert.isString('type', type);
switch (type) { switch (type) {
case (OrderbookChannelMessageTypes.Snapshot): { case OrderbookChannelMessageTypes.Snapshot: {
assert.doesConformToSchema('message', messageObj, schemas.relayerApiOrderbookChannelSnapshotSchema); assert.doesConformToSchema('message', messageObj, schemas.relayerApiOrderbookChannelSnapshotSchema);
const orderbook = messageObj.payload; const orderbook = messageObj.payload;
typeConverters.convertOrderbookStringFieldsToBigNumber(orderbook); typeConverters.convertOrderbookStringFieldsToBigNumber(orderbook);
return messageObj; return messageObj;
} }
case (OrderbookChannelMessageTypes.Update): { case OrderbookChannelMessageTypes.Update: {
assert.doesConformToSchema('message', messageObj, schemas.relayerApiOrderbookChannelUpdateSchema); assert.doesConformToSchema('message', messageObj, schemas.relayerApiOrderbookChannelUpdateSchema);
const order = messageObj.payload; const order = messageObj.payload;
typeConverters.convertOrderStringFieldsToBigNumber(order); typeConverters.convertOrderStringFieldsToBigNumber(order);

View File

@ -41,7 +41,10 @@ export class WebSocketOrderbookChannel implements OrderbookChannel {
*/ */
public subscribe(subscriptionOpts: OrderbookChannelSubscriptionOpts, handler: OrderbookChannelHandler): void { public subscribe(subscriptionOpts: OrderbookChannelSubscriptionOpts, handler: OrderbookChannelHandler): void {
assert.doesConformToSchema( assert.doesConformToSchema(
'subscriptionOpts', subscriptionOpts, schemas.relayerApiOrderbookChannelSubscribePayload); 'subscriptionOpts',
subscriptionOpts,
schemas.relayerApiOrderbookChannelSubscribePayload,
);
assert.isFunction('handler.onSnapshot', _.get(handler, 'onSnapshot')); assert.isFunction('handler.onSnapshot', _.get(handler, 'onSnapshot'));
assert.isFunction('handler.onUpdate', _.get(handler, 'onUpdate')); assert.isFunction('handler.onUpdate', _.get(handler, 'onUpdate'));
assert.isFunction('handler.onError', _.get(handler, 'onError')); assert.isFunction('handler.onError', _.get(handler, 'onError'));
@ -92,25 +95,32 @@ export class WebSocketOrderbookChannel implements OrderbookChannel {
this._client.connect(this._apiEndpointUrl); this._client.connect(this._apiEndpointUrl);
} }
} }
private _handleWebSocketMessage(requestId: number, subscriptionOpts: OrderbookChannelSubscriptionOpts, private _handleWebSocketMessage(
message: WebSocket.IMessage, handler: OrderbookChannelHandler): void { requestId: number,
subscriptionOpts: OrderbookChannelSubscriptionOpts,
message: WebSocket.IMessage,
handler: OrderbookChannelHandler,
): void {
if (!_.isUndefined(message.utf8Data)) { if (!_.isUndefined(message.utf8Data)) {
try { try {
const utf8Data = message.utf8Data; const utf8Data = message.utf8Data;
const parserResult = orderbookChannelMessageParsers.parser(utf8Data); const parserResult = orderbookChannelMessageParsers.parser(utf8Data);
if (parserResult.requestId === requestId) { if (parserResult.requestId === requestId) {
switch (parserResult.type) { switch (parserResult.type) {
case (OrderbookChannelMessageTypes.Snapshot): { case OrderbookChannelMessageTypes.Snapshot: {
handler.onSnapshot(this, subscriptionOpts, parserResult.payload); handler.onSnapshot(this, subscriptionOpts, parserResult.payload);
break; break;
} }
case (OrderbookChannelMessageTypes.Update): { case OrderbookChannelMessageTypes.Update: {
handler.onUpdate(this, subscriptionOpts, parserResult.payload); handler.onUpdate(this, subscriptionOpts, parserResult.payload);
break; break;
} }
default: { default: {
handler.onError( handler.onError(
this, subscriptionOpts, new Error(`Message has missing a type parameter: ${utf8Data}`)); this,
subscriptionOpts,
new Error(`Message has missing a type parameter: ${utf8Data}`),
);
} }
} }
} }

View File

@ -9,9 +9,7 @@ import {HttpClient} from '../src/index';
import { feesResponse } from './fixtures/standard_relayer_api/fees'; import { feesResponse } from './fixtures/standard_relayer_api/fees';
import * as feesResponseJSON from './fixtures/standard_relayer_api/fees.json'; import * as feesResponseJSON from './fixtures/standard_relayer_api/fees.json';
import { import { orderResponse } from './fixtures/standard_relayer_api/order/0xabc67323774bdbd24d94f977fa9ac94a50f016026fd13f42990861238897721f';
orderResponse,
} from './fixtures/standard_relayer_api/order/0xabc67323774bdbd24d94f977fa9ac94a50f016026fd13f42990861238897721f';
// tslint:disable-next-line:max-line-length // tslint:disable-next-line:max-line-length
import * as orderResponseJSON from './fixtures/standard_relayer_api/order/0xabc67323774bdbd24d94f977fa9ac94a50f016026fd13f42990861238897721f.json'; import * as orderResponseJSON from './fixtures/standard_relayer_api/order/0xabc67323774bdbd24d94f977fa9ac94a50f016026fd13f42990861238897721f.json';
import { orderbookResponse } from './fixtures/standard_relayer_api/orderbook'; import { orderbookResponse } from './fixtures/standard_relayer_api/orderbook';
@ -95,7 +93,9 @@ describe('HttpClient', () => {
quoteTokenAddress: '0xa2b31dacf30a9c50ca473337c01d8a201ae33e32', quoteTokenAddress: '0xa2b31dacf30a9c50ca473337c01d8a201ae33e32',
}; };
// tslint:disable-next-line:max-line-length // tslint:disable-next-line:max-line-length
const url = `${relayUrl}/v0/orderbook?baseTokenAddress=${request.baseTokenAddress}&quoteTokenAddress=${request.quoteTokenAddress}`; const url = `${relayUrl}/v0/orderbook?baseTokenAddress=${request.baseTokenAddress}&quoteTokenAddress=${
request.quoteTokenAddress
}`;
it('gets order book', async () => { it('gets order book', async () => {
fetchMock.get(url, orderbookJSON); fetchMock.get(url, orderbookJSON);
const orderbook = await relayerClient.getOrderbookAsync(request); const orderbook = await relayerClient.getOrderbookAsync(request);

View File

@ -58,15 +58,14 @@ describe('orderbookChannelMessageParsers', () => {
expect(badCall).throws('Expected type to be of type string, encountered: 1'); expect(badCall).throws('Expected type to be of type string, encountered: 1');
}); });
it('throws when snapshot message has malformed payload', () => { it('throws when snapshot message has malformed payload', () => {
const badCall = () => const badCall = () => orderbookChannelMessageParsers.parser(malformedSnapshotOrderbookChannelMessage);
orderbookChannelMessageParsers.parser(malformedSnapshotOrderbookChannelMessage);
// tslint:disable-next-line:max-line-length // tslint:disable-next-line:max-line-length
const errMsg = 'Validation errors: instance.payload requires property "bids", instance.payload requires property "asks"'; const errMsg =
'Validation errors: instance.payload requires property "bids", instance.payload requires property "asks"';
expect(badCall).throws(errMsg); expect(badCall).throws(errMsg);
}); });
it('throws when update message has malformed payload', () => { it('throws when update message has malformed payload', () => {
const badCall = () => const badCall = () => orderbookChannelMessageParsers.parser(malformedUpdateOrderbookChannelMessage);
orderbookChannelMessageParsers.parser(malformedUpdateOrderbookChannelMessage);
expect(badCall).throws(/^Expected message to conform to schema/); expect(badCall).throws(/^Expected message to conform to schema/);
}); });
it('throws when input message is not valid JSON', () => { it('throws when input message is not valid JSON', () => {

View File

@ -3,9 +3,7 @@ import * as dirtyChai from 'dirty-chai';
import * as _ from 'lodash'; import * as _ from 'lodash';
import 'mocha'; import 'mocha';
import { import { WebSocketOrderbookChannel } from '../src/ws_orderbook_channel';
WebSocketOrderbookChannel,
} from '../src/ws_orderbook_channel';
chai.config.includeStack = true; chai.config.includeStack = true;
chai.use(dirtyChai); chai.use(dirtyChai);
@ -21,26 +19,43 @@ describe('WebSocketOrderbookChannel', () => {
limit: 100, limit: 100,
}; };
const emptyOrderbookChannelHandler = { const emptyOrderbookChannelHandler = {
onSnapshot: () => { _.noop(); }, onSnapshot: () => {
onUpdate: () => { _.noop(); }, _.noop();
onError: () => { _.noop(); }, },
onClose: () => { _.noop(); }, onUpdate: () => {
_.noop();
},
onError: () => {
_.noop();
},
onClose: () => {
_.noop();
},
}; };
describe('#subscribe', () => { describe('#subscribe', () => {
it('throws when subscriptionOpts does not conform to schema', () => { it('throws when subscriptionOpts does not conform to schema', () => {
const badSubscribeCall = orderbookChannel.subscribe.bind( const badSubscribeCall = orderbookChannel.subscribe.bind(
orderbookChannel, {}, emptyOrderbookChannelHandler); orderbookChannel,
{},
emptyOrderbookChannelHandler,
);
// tslint:disable-next-line:max-line-length // tslint:disable-next-line:max-line-length
expect(badSubscribeCall).throws('Expected subscriptionOpts to conform to schema /RelayerApiOrderbookChannelSubscribePayload\nEncountered: {}\nValidation errors: instance requires property "baseTokenAddress", instance requires property "quoteTokenAddress"'); expect(badSubscribeCall).throws(
'Expected subscriptionOpts to conform to schema /RelayerApiOrderbookChannelSubscribePayload\nEncountered: {}\nValidation errors: instance requires property "baseTokenAddress", instance requires property "quoteTokenAddress"',
);
}); });
it('throws when handler has the incorrect members', () => { it('throws when handler has the incorrect members', () => {
const badSubscribeCall = orderbookChannel.subscribe.bind(orderbookChannel, subscriptionOpts, {}); const badSubscribeCall = orderbookChannel.subscribe.bind(orderbookChannel, subscriptionOpts, {});
expect(badSubscribeCall) expect(badSubscribeCall).throws(
.throws('Expected handler.onSnapshot to be of type function, encountered: undefined'); 'Expected handler.onSnapshot to be of type function, encountered: undefined',
);
}); });
it('does not throw when inputs are of correct types', () => { it('does not throw when inputs are of correct types', () => {
const goodSubscribeCall = orderbookChannel.subscribe.bind( const goodSubscribeCall = orderbookChannel.subscribe.bind(
orderbookChannel, subscriptionOpts, emptyOrderbookChannelHandler); orderbookChannel,
subscriptionOpts,
emptyOrderbookChannelHandler,
);
expect(goodSubscribeCall).to.not.throw(); expect(goodSubscribeCall).to.not.throw();
}); });
}); });

View File

@ -6,18 +6,14 @@ import * as Web3 from 'web3';
import * as yargs from 'yargs'; import * as yargs from 'yargs';
import { commands } from './src/commands'; import { commands } from './src/commands';
import { import { CliOptions, CompilerOptions, DeployerOptions } from './src/utils/types';
CliOptions,
CompilerOptions,
DeployerOptions,
} from './src/utils/types';
const DEFAULT_OPTIMIZER_ENABLED = false; const DEFAULT_OPTIMIZER_ENABLED = false;
const DEFAULT_CONTRACTS_DIR = path.resolve('contracts'); const DEFAULT_CONTRACTS_DIR = path.resolve('contracts');
const DEFAULT_ARTIFACTS_DIR = `${path.resolve('build')}/artifacts/`; const DEFAULT_ARTIFACTS_DIR = `${path.resolve('build')}/artifacts/`;
const DEFAULT_NETWORK_ID = 50; const DEFAULT_NETWORK_ID = 50;
const DEFAULT_JSONRPC_PORT = 8545; const DEFAULT_JSONRPC_PORT = 8545;
const DEFAULT_GAS_PRICE = ((10 ** 9) * 2).toString(); const DEFAULT_GAS_PRICE = (10 ** 9 * 2).toString();
/** /**
* Compiles all contracts with options passed in through CLI. * Compiles all contracts with options passed in through CLI.
@ -108,8 +104,7 @@ function deployCommandBuilder(yargsInstance: any) {
description: 'comma separated list of constructor args to deploy contract with', description: 'comma separated list of constructor args to deploy contract with',
}) })
.demandOption(['contract', 'args']) .demandOption(['contract', 'args'])
.help() .help().argv;
.argv;
} }
(() => { (() => {
@ -149,18 +144,13 @@ function deployCommandBuilder(yargsInstance: any) {
type: 'string', type: 'string',
description: 'account to use for deploying contracts', description: 'account to use for deploying contracts',
}) })
.command('compile', .command('compile', 'compile contracts', identityCommandBuilder, onCompileCommand)
'compile contracts', .command(
identityCommandBuilder, 'migrate',
onCompileCommand)
.command('migrate',
'compile and deploy contracts using migration scripts', 'compile and deploy contracts using migration scripts',
identityCommandBuilder, identityCommandBuilder,
onMigrateCommand) onMigrateCommand,
.command('deploy', )
'deploy a single contract with provided arguments', .command('deploy', 'deploy a single contract with provided arguments', deployCommandBuilder, onDeployCommand)
deployCommandBuilder, .help().argv;
onDeployCommand)
.help()
.argv;
})(); })();

View File

@ -29,7 +29,8 @@ export const migrator = {
const multiSigArgs = [owners, confirmationsRequired, secondsRequired, tokenTransferProxy.address]; const multiSigArgs = [owners, confirmationsRequired, secondsRequired, tokenTransferProxy.address];
const exchange = await deployer.deployAndSaveAsync('Exchange', exchangeArgs); const exchange = await deployer.deployAndSaveAsync('Exchange', exchangeArgs);
const multiSig = await deployer.deployAndSaveAsync( const multiSig = await deployer.deployAndSaveAsync(
'MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress', multiSigArgs, 'MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress',
multiSigArgs,
); );
const owner = accounts[0]; const owner = accounts[0];
@ -70,12 +71,7 @@ export const migrator = {
); );
for (const token of tokenInfo) { for (const token of tokenInfo) {
const totalSupply = new BigNumber(0); const totalSupply = new BigNumber(0);
const args = [ const args = [token.name, token.symbol, token.decimals, totalSupply];
token.name,
token.symbol,
token.decimals,
totalSupply,
];
const dummyToken = await deployer.deployAsync('DummyToken', args); const dummyToken = await deployer.deployAsync('DummyToken', args);
await tokenReg.addToken.sendTransactionAsync( await tokenReg.addToken.sendTransactionAsync(
dummyToken.address, dummyToken.address,

View File

@ -150,7 +150,8 @@ export class Compiler {
currentArtifact = JSON.parse(currentArtifactString); currentArtifact = JSON.parse(currentArtifactString);
oldNetworks = currentArtifact.networks; oldNetworks = currentArtifact.networks;
const oldNetwork: ContractData = oldNetworks[this._networkId]; const oldNetwork: ContractData = oldNetworks[this._networkId];
shouldCompile = _.isUndefined(oldNetwork) || shouldCompile =
_.isUndefined(oldNetwork) ||
oldNetwork.keccak256 !== sourceHash || oldNetwork.keccak256 !== sourceHash ||
oldNetwork.optimizer_enabled !== this._optimizerEnabled; oldNetwork.optimizer_enabled !== this._optimizerEnabled;
} catch (err) { } catch (err) {
@ -174,9 +175,11 @@ export class Compiler {
const sourcesToCompile = { const sourcesToCompile = {
sources: input, sources: input,
}; };
const compiled = solcInstance.compile(sourcesToCompile, const compiled = solcInstance.compile(
sourcesToCompile,
this._optimizerEnabled, this._optimizerEnabled,
this._findImportsIfSourcesExist.bind(this)); this._findImportsIfSourcesExist.bind(this),
);
if (!_.isUndefined(compiled.errors)) { if (!_.isUndefined(compiled.errors)) {
_.each(compiled.errors, errMsg => { _.each(compiled.errors, errMsg => {

View File

@ -6,11 +6,7 @@ import * as Web3 from 'web3';
import { Contract } from './utils/contract'; import { Contract } from './utils/contract';
import { encoder } from './utils/encoder'; import { encoder } from './utils/encoder';
import { fsWrapper } from './utils/fs_wrapper'; import { fsWrapper } from './utils/fs_wrapper';
import { import { ContractArtifact, ContractData, DeployerOptions } from './utils/types';
ContractArtifact,
ContractData,
DeployerOptions,
} from './utils/types';
import { utils } from './utils/utils'; import { utils } from './utils/utils';
// Gas added to gas estimate to make sure there is sufficient gas for deployment. // Gas added to gas estimate to make sure there is sufficient gas for deployment.
@ -99,8 +95,11 @@ export class Deployer {
* @param contractAddress Contract address to save to artifact. * @param contractAddress Contract address to save to artifact.
* @param args Contract constructor arguments that will be encoded and saved to artifact. * @param args Contract constructor arguments that will be encoded and saved to artifact.
*/ */
private async _saveContractDataToArtifactAsync(contractName: string, private async _saveContractDataToArtifactAsync(
contractAddress: string, args: any[]): Promise<void> { contractName: string,
contractAddress: string,
args: any[],
): Promise<void> {
const contractArtifact: ContractArtifact = this._loadContractArtifactIfExists(contractName); const contractArtifact: ContractArtifact = this._loadContractArtifactIfExists(contractName);
const contractData: ContractData = this._getContractDataFromArtifactIfExists(contractArtifact); const contractData: ContractData = this._getContractDataFromArtifactIfExists(contractArtifact);
const abi = contractData.abi; const abi = contractData.abi;

File diff suppressed because one or more lines are too long

View File

@ -1,11 +1,6 @@
import { Artifacts } from '../util/artifacts'; import { Artifacts } from '../util/artifacts';
import { MultiSigConfigByNetwork } from '../util/types'; import { MultiSigConfigByNetwork } from '../util/types';
const { const { MultiSigWalletWithTimeLock, TokenTransferProxy, EtherToken, TokenRegistry } = new Artifacts(artifacts);
MultiSigWalletWithTimeLock,
TokenTransferProxy,
EtherToken,
TokenRegistry,
} = new Artifacts(artifacts);
let multiSigConfigByNetwork: MultiSigConfigByNetwork; let multiSigConfigByNetwork: MultiSigConfigByNetwork;
try { try {
@ -25,13 +20,15 @@ module.exports = (deployer: any, network: string, accounts: string[]) => {
}; };
const config = multiSigConfigByNetwork[network] || defaultConfig; const config = multiSigConfigByNetwork[network] || defaultConfig;
if (network !== 'live') { if (network !== 'live') {
deployer.deploy(MultiSigWalletWithTimeLock, config.owners, deployer
config.confirmationsRequired, config.secondsRequired) .deploy(MultiSigWalletWithTimeLock, config.owners, config.confirmationsRequired, config.secondsRequired)
.then(() => { .then(() => {
return deployer.deploy(TokenTransferProxy); return deployer.deploy(TokenTransferProxy);
}).then(() => { })
.then(() => {
return deployer.deploy(TokenRegistry); return deployer.deploy(TokenRegistry);
}).then(() => { })
.then(() => {
return deployer.deploy(EtherToken); return deployer.deploy(EtherToken);
}); });
} else { } else {

View File

@ -6,26 +6,21 @@ import {constants} from '../util/constants';
import { ContractInstance, Token } from '../util/types'; import { ContractInstance, Token } from '../util/types';
import { tokenInfo } from './config/token_info'; import { tokenInfo } from './config/token_info';
const { const { DummyToken, EtherToken, ZRXToken, TokenRegistry } = new Artifacts(artifacts);
DummyToken,
EtherToken,
ZRXToken,
TokenRegistry,
} = new Artifacts(artifacts);
module.exports = (deployer: any, network: string) => { module.exports = (deployer: any, network: string) => {
const tokens = network === 'live' ? tokenInfo.live : tokenInfo.development; const tokens = network === 'live' ? tokenInfo.live : tokenInfo.development;
deployer.then(() => { deployer
.then(() => {
return TokenRegistry.deployed(); return TokenRegistry.deployed();
}).then((tokenRegistry: ContractInstance) => { })
.then((tokenRegistry: ContractInstance) => {
if (network !== 'live') { if (network !== 'live') {
const totalSupply = Math.pow(10, 18) * 1000000000; const totalSupply = Math.pow(10, 18) * 1000000000;
return Bluebird.each(tokens.map((token: Token) => DummyToken.new( return Bluebird.each(
token.name, tokens.map((token: Token) => DummyToken.new(token.name, token.symbol, token.decimals, totalSupply)),
token.symbol, _.noop,
token.decimals, ).then((dummyTokens: ContractInstance[]) => {
totalSupply,
)), _.noop).then((dummyTokens: ContractInstance[]) => {
const weth = { const weth = {
address: EtherToken.address, address: EtherToken.address,
name: 'Ether Token', name: 'Ether Token',
@ -35,7 +30,9 @@ module.exports = (deployer: any, network: string) => {
ipfsHash: constants.NULL_BYTES, ipfsHash: constants.NULL_BYTES,
swarmHash: constants.NULL_BYTES, swarmHash: constants.NULL_BYTES,
}; };
return Bluebird.each(dummyTokens.map((tokenContract: ContractInstance, i: number) => { return Bluebird.each(
dummyTokens
.map((tokenContract: ContractInstance, i: number) => {
const token = tokens[i]; const token = tokens[i];
return tokenRegistry.addToken( return tokenRegistry.addToken(
tokenContract.address, tokenContract.address,
@ -45,14 +42,19 @@ module.exports = (deployer: any, network: string) => {
token.ipfsHash, token.ipfsHash,
token.swarmHash, token.swarmHash,
); );
}).concat(tokenRegistry.addToken( })
.concat(
tokenRegistry.addToken(
weth.address, weth.address,
weth.name, weth.name,
weth.symbol, weth.symbol,
weth.decimals, weth.decimals,
weth.ipfsHash, weth.ipfsHash,
weth.swarmHash, weth.swarmHash,
)), _.noop); ),
),
_.noop,
);
}); });
} else { } else {
const zrx = { const zrx = {
@ -64,7 +66,9 @@ module.exports = (deployer: any, network: string) => {
ipfsHash: constants.NULL_BYTES, ipfsHash: constants.NULL_BYTES,
swarmHash: constants.NULL_BYTES, swarmHash: constants.NULL_BYTES,
}; };
return Bluebird.each(tokens.map((token: Token) => { return Bluebird.each(
tokens
.map((token: Token) => {
return tokenRegistry.addToken( return tokenRegistry.addToken(
token.address, token.address,
token.name, token.name,
@ -73,14 +77,19 @@ module.exports = (deployer: any, network: string) => {
token.ipfsHash, token.ipfsHash,
token.swarmHash, token.swarmHash,
); );
}).concat(tokenRegistry.addToken( })
.concat(
tokenRegistry.addToken(
zrx.address, zrx.address,
zrx.name, zrx.name,
zrx.symbol, zrx.symbol,
zrx.decimals, zrx.decimals,
zrx.ipfsHash, zrx.ipfsHash,
zrx.swarmHash, zrx.swarmHash,
)), _.noop); ),
),
_.noop,
);
} }
}); });
}; };

View File

@ -1,18 +1,12 @@
import { Artifacts } from '../util/artifacts'; import { Artifacts } from '../util/artifacts';
import { ContractInstance } from '../util/types'; import { ContractInstance } from '../util/types';
const { const { TokenTransferProxy, Exchange, TokenRegistry } = new Artifacts(artifacts);
TokenTransferProxy,
Exchange,
TokenRegistry,
} = new Artifacts(artifacts);
let tokenTransferProxy: ContractInstance; let tokenTransferProxy: ContractInstance;
module.exports = (deployer: any) => { module.exports = (deployer: any) => {
deployer.then(async () => { deployer
return Promise.all([ .then(async () => {
TokenTransferProxy.deployed(), return Promise.all([TokenTransferProxy.deployed(), TokenRegistry.deployed()]);
TokenRegistry.deployed(),
]);
}) })
.then((instances: ContractInstance[]) => { .then((instances: ContractInstance[]) => {
let tokenRegistry: ContractInstance; let tokenRegistry: ContractInstance;
@ -21,7 +15,8 @@ module.exports = (deployer: any) => {
}) })
.then((ptAddress: string) => { .then((ptAddress: string) => {
return deployer.deploy(Exchange, ptAddress, tokenTransferProxy.address); return deployer.deploy(Exchange, ptAddress, tokenTransferProxy.address);
}).then(() => { })
.then(() => {
return tokenTransferProxy.addAuthorizedAddress(Exchange.address); return tokenTransferProxy.addAuthorizedAddress(Exchange.address);
}); });
}; };

View File

@ -1,23 +1,18 @@
import { Artifacts } from '../util/artifacts'; import { Artifacts } from '../util/artifacts';
import { ContractInstance } from '../util/types'; import { ContractInstance } from '../util/types';
const { const { TokenTransferProxy, MultiSigWalletWithTimeLock, TokenRegistry } = new Artifacts(artifacts);
TokenTransferProxy,
MultiSigWalletWithTimeLock,
TokenRegistry,
} = new Artifacts(artifacts);
let tokenRegistry: ContractInstance; let tokenRegistry: ContractInstance;
module.exports = (deployer: any, network: string) => { module.exports = (deployer: any, network: string) => {
if (network !== 'development') { if (network !== 'development') {
deployer.then(async () => { deployer.then(async () => {
return Promise.all([ return Promise.all([TokenTransferProxy.deployed(), TokenRegistry.deployed()])
TokenTransferProxy.deployed(), .then((instances: ContractInstance[]) => {
TokenRegistry.deployed(),
]).then((instances: ContractInstance[]) => {
let tokenTransferProxy: ContractInstance; let tokenTransferProxy: ContractInstance;
[tokenTransferProxy, tokenRegistry] = instances; [tokenTransferProxy, tokenRegistry] = instances;
return tokenTransferProxy.transferOwnership(MultiSigWalletWithTimeLock.address); return tokenTransferProxy.transferOwnership(MultiSigWalletWithTimeLock.address);
}).then(() => { })
.then(() => {
return tokenRegistry.transferOwnership(MultiSigWalletWithTimeLock.address); return tokenRegistry.transferOwnership(MultiSigWalletWithTimeLock.address);
}); });
}); });

View File

@ -44,8 +44,9 @@ contract('EtherToken', (accounts: string[]) => {
const initEthBalance = await getEthBalanceAsync(account); const initEthBalance = await getEthBalanceAsync(account);
const ethToDeposit = initEthBalance.plus(1); const ethToDeposit = initEthBalance.plus(1);
return expect(zeroEx.etherToken.depositAsync(etherTokenAddress, ethToDeposit, account)) return expect(zeroEx.etherToken.depositAsync(etherTokenAddress, ethToDeposit, account)).to.be.rejectedWith(
.to.be.rejectedWith(ZeroExError.InsufficientEthBalanceForDeposit); ZeroExError.InsufficientEthBalanceForDeposit,
);
}); });
it('should convert deposited Ether to wrapped Ether tokens', async () => { it('should convert deposited Ether to wrapped Ether tokens', async () => {
@ -71,8 +72,9 @@ contract('EtherToken', (accounts: string[]) => {
const initEthTokenBalance = await zeroEx.token.getBalanceAsync(etherTokenAddress, account); const initEthTokenBalance = await zeroEx.token.getBalanceAsync(etherTokenAddress, account);
const ethTokensToWithdraw = initEthTokenBalance.plus(1); const ethTokensToWithdraw = initEthTokenBalance.plus(1);
return expect(zeroEx.etherToken.withdrawAsync(etherTokenAddress, ethTokensToWithdraw, account)) return expect(
.to.be.rejectedWith(ZeroExError.InsufficientWEthBalanceForWithdrawal); zeroEx.etherToken.withdrawAsync(etherTokenAddress, ethTokensToWithdraw, account),
).to.be.rejectedWith(ZeroExError.InsufficientWEthBalanceForWithdrawal);
}); });
it('should convert ether tokens to ether with sufficient balance', async () => { it('should convert ether tokens to ether with sufficient balance', async () => {
@ -89,8 +91,9 @@ contract('EtherToken', (accounts: string[]) => {
const finalEthBalance = await getEthBalanceAsync(account); const finalEthBalance = await getEthBalanceAsync(account);
const finalEthTokenBalance = await zeroEx.token.getBalanceAsync(etherTokenAddress, account); const finalEthTokenBalance = await zeroEx.token.getBalanceAsync(etherTokenAddress, account);
expect(finalEthBalance).to.be.bignumber expect(finalEthBalance).to.be.bignumber.equal(
.equal(initEthBalance.plus(ethTokensToWithdraw.minus(ethSpentOnGas))); initEthBalance.plus(ethTokensToWithdraw.minus(ethSpentOnGas)),
);
expect(finalEthTokenBalance).to.be.bignumber.equal(initEthTokenBalance.minus(ethTokensToWithdraw)); expect(finalEthTokenBalance).to.be.bignumber.equal(initEthTokenBalance.minus(ethTokensToWithdraw));
}); });
}); });

View File

@ -16,13 +16,7 @@ import {chaiSetup} from '../utils/chai_setup';
chaiSetup.configure(); chaiSetup.configure();
const expect = chai.expect; const expect = chai.expect;
const { const { Exchange, TokenTransferProxy, DummyToken, TokenRegistry, MaliciousToken } = new Artifacts(artifacts);
Exchange,
TokenTransferProxy,
DummyToken,
TokenRegistry,
MaliciousToken,
} = new Artifacts(artifacts);
// In order to benefit from type-safety, we re-assign the global web3 instance injected by Truffle // In order to benefit from type-safety, we re-assign the global web3 instance injected by Truffle
// with type `any` to a variable of type `Web3`. // with type `any` to a variable of type `Web3`.
@ -52,10 +46,7 @@ contract('Exchange', (accounts: string[]) => {
let zeroEx: ZeroEx; let zeroEx: ZeroEx;
before(async () => { before(async () => {
[tokenRegistry, exchange] = await Promise.all([ [tokenRegistry, exchange] = await Promise.all([TokenRegistry.deployed(), Exchange.deployed()]);
TokenRegistry.deployed(),
Exchange.deployed(),
]);
exWrapper = new ExchangeWrapper(exchange); exWrapper = new ExchangeWrapper(exchange);
zeroEx = new ZeroEx(web3.currentProvider, { zeroEx = new ZeroEx(web3.currentProvider, {
exchangeContractAddress: exchange.address, exchangeContractAddress: exchange.address,
@ -88,16 +79,28 @@ contract('Exchange', (accounts: string[]) => {
]); ]);
dmyBalances = new Balances([rep, dgd, zrx], [maker, taker, feeRecipient]); dmyBalances = new Balances([rep, dgd, zrx], [maker, taker, feeRecipient]);
await Promise.all([ await Promise.all([
rep.approve(TokenTransferProxy.address, INITIAL_ALLOWANCE, {from: maker}), rep.approve(TokenTransferProxy.address, INITIAL_ALLOWANCE, {
rep.approve(TokenTransferProxy.address, INITIAL_ALLOWANCE, {from: taker}), from: maker,
}),
rep.approve(TokenTransferProxy.address, INITIAL_ALLOWANCE, {
from: taker,
}),
rep.setBalance(maker, INITIAL_BALANCE, { from: tokenOwner }), rep.setBalance(maker, INITIAL_BALANCE, { from: tokenOwner }),
rep.setBalance(taker, INITIAL_BALANCE, { from: tokenOwner }), rep.setBalance(taker, INITIAL_BALANCE, { from: tokenOwner }),
dgd.approve(TokenTransferProxy.address, INITIAL_ALLOWANCE, {from: maker}), dgd.approve(TokenTransferProxy.address, INITIAL_ALLOWANCE, {
dgd.approve(TokenTransferProxy.address, INITIAL_ALLOWANCE, {from: taker}), from: maker,
}),
dgd.approve(TokenTransferProxy.address, INITIAL_ALLOWANCE, {
from: taker,
}),
dgd.setBalance(maker, INITIAL_BALANCE, { from: tokenOwner }), dgd.setBalance(maker, INITIAL_BALANCE, { from: tokenOwner }),
dgd.setBalance(taker, INITIAL_BALANCE, { from: tokenOwner }), dgd.setBalance(taker, INITIAL_BALANCE, { from: tokenOwner }),
zrx.approve(TokenTransferProxy.address, INITIAL_ALLOWANCE, {from: maker}), zrx.approve(TokenTransferProxy.address, INITIAL_ALLOWANCE, {
zrx.approve(TokenTransferProxy.address, INITIAL_ALLOWANCE, {from: taker}), from: maker,
}),
zrx.approve(TokenTransferProxy.address, INITIAL_ALLOWANCE, {
from: taker,
}),
zrx.setBalance(maker, INITIAL_BALANCE, { from: tokenOwner }), zrx.setBalance(maker, INITIAL_BALANCE, { from: tokenOwner }),
zrx.setBalance(taker, INITIAL_BALANCE, { from: tokenOwner }), zrx.setBalance(taker, INITIAL_BALANCE, { from: tokenOwner }),
]); ]);
@ -133,22 +136,29 @@ contract('Exchange', (accounts: string[]) => {
takerTokenAmount: new BigNumber(3), takerTokenAmount: new BigNumber(3),
}); });
const filledTakerTokenAmountBefore = const filledTakerTokenAmountBefore = await zeroEx.exchange.getFilledTakerAmountAsync(
await zeroEx.exchange.getFilledTakerAmountAsync(order.params.orderHashHex); order.params.orderHashHex,
);
expect(filledTakerTokenAmountBefore).to.be.bignumber.equal(0); expect(filledTakerTokenAmountBefore).to.be.bignumber.equal(0);
const fillTakerTokenAmount1 = new BigNumber(2); const fillTakerTokenAmount1 = new BigNumber(2);
await exWrapper.fillOrderAsync(order, taker, {fillTakerTokenAmount: fillTakerTokenAmount1}); await exWrapper.fillOrderAsync(order, taker, {
fillTakerTokenAmount: fillTakerTokenAmount1,
});
const filledTakerTokenAmountAfter1 = const filledTakerTokenAmountAfter1 = await zeroEx.exchange.getFilledTakerAmountAsync(
await zeroEx.exchange.getFilledTakerAmountAsync(order.params.orderHashHex); order.params.orderHashHex,
);
expect(filledTakerTokenAmountAfter1).to.be.bignumber.equal(fillTakerTokenAmount1); expect(filledTakerTokenAmountAfter1).to.be.bignumber.equal(fillTakerTokenAmount1);
const fillTakerTokenAmount2 = new BigNumber(1); const fillTakerTokenAmount2 = new BigNumber(1);
await exWrapper.fillOrderAsync(order, taker, {fillTakerTokenAmount: fillTakerTokenAmount2}); await exWrapper.fillOrderAsync(order, taker, {
fillTakerTokenAmount: fillTakerTokenAmount2,
});
const filledTakerTokenAmountAfter2 = const filledTakerTokenAmountAfter2 = await zeroEx.exchange.getFilledTakerAmountAsync(
await zeroEx.exchange.getFilledTakerAmountAsync(order.params.orderHashHex); order.params.orderHashHex,
);
expect(filledTakerTokenAmountAfter2).to.be.bignumber.equal(filledTakerTokenAmountAfter1); expect(filledTakerTokenAmountAfter2).to.be.bignumber.equal(filledTakerTokenAmountAfter1);
}); });
@ -158,15 +168,17 @@ contract('Exchange', (accounts: string[]) => {
takerTokenAmount: ZeroEx.toBaseUnitAmount(new BigNumber(100), 18), takerTokenAmount: ZeroEx.toBaseUnitAmount(new BigNumber(100), 18),
}); });
const filledTakerTokenAmountBefore = const filledTakerTokenAmountBefore = await zeroEx.exchange.getFilledTakerAmountAsync(
await zeroEx.exchange.getFilledTakerAmountAsync(order.params.orderHashHex); order.params.orderHashHex,
);
expect(filledTakerTokenAmountBefore).to.be.bignumber.equal(0); expect(filledTakerTokenAmountBefore).to.be.bignumber.equal(0);
const fillTakerTokenAmount = order.params.takerTokenAmount.div(2); const fillTakerTokenAmount = order.params.takerTokenAmount.div(2);
await exWrapper.fillOrderAsync(order, taker, { fillTakerTokenAmount }); await exWrapper.fillOrderAsync(order, taker, { fillTakerTokenAmount });
const filledTakerTokenAmountAfter = const filledTakerTokenAmountAfter = await zeroEx.exchange.getFilledTakerAmountAsync(
await zeroEx.exchange.getFilledTakerAmountAsync(order.params.orderHashHex); order.params.orderHashHex,
);
expect(filledTakerTokenAmountAfter).to.be.bignumber.equal(fillTakerTokenAmount); expect(filledTakerTokenAmountAfter).to.be.bignumber.equal(fillTakerTokenAmount);
const newBalances = await dmyBalances.getAsync(); const newBalances = await dmyBalances.getAsync();
@ -180,20 +192,27 @@ contract('Exchange', (accounts: string[]) => {
const paidTakerFee = order.params.takerFee const paidTakerFee = order.params.takerFee
.times(fillMakerTokenAmount) .times(fillMakerTokenAmount)
.dividedToIntegerBy(order.params.makerTokenAmount); .dividedToIntegerBy(order.params.makerTokenAmount);
expect(newBalances[maker][order.params.makerToken]) expect(newBalances[maker][order.params.makerToken]).to.be.bignumber.equal(
.to.be.bignumber.equal(balances[maker][order.params.makerToken].minus(fillMakerTokenAmount)); balances[maker][order.params.makerToken].minus(fillMakerTokenAmount),
expect(newBalances[maker][order.params.takerToken]) );
.to.be.bignumber.equal(balances[maker][order.params.takerToken].add(fillTakerTokenAmount)); expect(newBalances[maker][order.params.takerToken]).to.be.bignumber.equal(
expect(newBalances[maker][zrx.address]).to.be.bignumber balances[maker][order.params.takerToken].add(fillTakerTokenAmount),
.equal(balances[maker][zrx.address].minus(paidMakerFee)); );
expect(newBalances[taker][order.params.takerToken]) expect(newBalances[maker][zrx.address]).to.be.bignumber.equal(
.to.be.bignumber.equal(balances[taker][order.params.takerToken].minus(fillTakerTokenAmount)); balances[maker][zrx.address].minus(paidMakerFee),
expect(newBalances[taker][order.params.makerToken]) );
.to.be.bignumber.equal(balances[taker][order.params.makerToken].add(fillMakerTokenAmount)); expect(newBalances[taker][order.params.takerToken]).to.be.bignumber.equal(
expect(newBalances[taker][zrx.address]).to.be.bignumber balances[taker][order.params.takerToken].minus(fillTakerTokenAmount),
.equal(balances[taker][zrx.address].minus(paidTakerFee)); );
expect(newBalances[feeRecipient][zrx.address]) expect(newBalances[taker][order.params.makerToken]).to.be.bignumber.equal(
.to.be.bignumber.equal(balances[feeRecipient][zrx.address].add(paidMakerFee.add(paidTakerFee))); balances[taker][order.params.makerToken].add(fillMakerTokenAmount),
);
expect(newBalances[taker][zrx.address]).to.be.bignumber.equal(
balances[taker][zrx.address].minus(paidTakerFee),
);
expect(newBalances[feeRecipient][zrx.address]).to.be.bignumber.equal(
balances[feeRecipient][zrx.address].add(paidMakerFee.add(paidTakerFee)),
);
}); });
it('should transfer the correct amounts when makerTokenAmount > takerTokenAmount', async () => { it('should transfer the correct amounts when makerTokenAmount > takerTokenAmount', async () => {
@ -202,15 +221,17 @@ contract('Exchange', (accounts: string[]) => {
takerTokenAmount: ZeroEx.toBaseUnitAmount(new BigNumber(100), 18), takerTokenAmount: ZeroEx.toBaseUnitAmount(new BigNumber(100), 18),
}); });
const filledTakerTokenAmountBefore = const filledTakerTokenAmountBefore = await zeroEx.exchange.getFilledTakerAmountAsync(
await zeroEx.exchange.getFilledTakerAmountAsync(order.params.orderHashHex); order.params.orderHashHex,
);
expect(filledTakerTokenAmountBefore).to.be.bignumber.equal(0); expect(filledTakerTokenAmountBefore).to.be.bignumber.equal(0);
const fillTakerTokenAmount = order.params.takerTokenAmount.div(2); const fillTakerTokenAmount = order.params.takerTokenAmount.div(2);
await exWrapper.fillOrderAsync(order, taker, { fillTakerTokenAmount }); await exWrapper.fillOrderAsync(order, taker, { fillTakerTokenAmount });
const filledTakerTokenAmountAfter = const filledTakerTokenAmountAfter = await zeroEx.exchange.getFilledTakerAmountAsync(
await zeroEx.exchange.getFilledTakerAmountAsync(order.params.orderHashHex); order.params.orderHashHex,
);
expect(filledTakerTokenAmountAfter).to.be.bignumber.equal(fillTakerTokenAmount); expect(filledTakerTokenAmountAfter).to.be.bignumber.equal(fillTakerTokenAmount);
const newBalances = await dmyBalances.getAsync(); const newBalances = await dmyBalances.getAsync();
@ -224,20 +245,27 @@ contract('Exchange', (accounts: string[]) => {
const paidTakerFee = order.params.takerFee const paidTakerFee = order.params.takerFee
.times(fillMakerTokenAmount) .times(fillMakerTokenAmount)
.dividedToIntegerBy(order.params.makerTokenAmount); .dividedToIntegerBy(order.params.makerTokenAmount);
expect(newBalances[maker][order.params.makerToken]) expect(newBalances[maker][order.params.makerToken]).to.be.bignumber.equal(
.to.be.bignumber.equal(balances[maker][order.params.makerToken].minus(fillMakerTokenAmount)); balances[maker][order.params.makerToken].minus(fillMakerTokenAmount),
expect(newBalances[maker][order.params.takerToken]) );
.to.be.bignumber.equal(balances[maker][order.params.takerToken].add(fillTakerTokenAmount)); expect(newBalances[maker][order.params.takerToken]).to.be.bignumber.equal(
expect(newBalances[maker][zrx.address]).to.be.bignumber balances[maker][order.params.takerToken].add(fillTakerTokenAmount),
.equal(balances[maker][zrx.address].minus(paidMakerFee)); );
expect(newBalances[taker][order.params.takerToken]) expect(newBalances[maker][zrx.address]).to.be.bignumber.equal(
.to.be.bignumber.equal(balances[taker][order.params.takerToken].minus(fillTakerTokenAmount)); balances[maker][zrx.address].minus(paidMakerFee),
expect(newBalances[taker][order.params.makerToken]) );
.to.be.bignumber.equal(balances[taker][order.params.makerToken].add(fillMakerTokenAmount)); expect(newBalances[taker][order.params.takerToken]).to.be.bignumber.equal(
expect(newBalances[taker][zrx.address]).to.be.bignumber balances[taker][order.params.takerToken].minus(fillTakerTokenAmount),
.equal(balances[taker][zrx.address].minus(paidTakerFee)); );
expect(newBalances[feeRecipient][zrx.address]) expect(newBalances[taker][order.params.makerToken]).to.be.bignumber.equal(
.to.be.bignumber.equal(balances[feeRecipient][zrx.address].add(paidMakerFee.add(paidTakerFee))); balances[taker][order.params.makerToken].add(fillMakerTokenAmount),
);
expect(newBalances[taker][zrx.address]).to.be.bignumber.equal(
balances[taker][zrx.address].minus(paidTakerFee),
);
expect(newBalances[feeRecipient][zrx.address]).to.be.bignumber.equal(
balances[feeRecipient][zrx.address].add(paidMakerFee.add(paidTakerFee)),
);
}); });
it('should transfer the correct amounts when makerTokenAmount < takerTokenAmount', async () => { it('should transfer the correct amounts when makerTokenAmount < takerTokenAmount', async () => {
@ -246,15 +274,17 @@ contract('Exchange', (accounts: string[]) => {
takerTokenAmount: ZeroEx.toBaseUnitAmount(new BigNumber(200), 18), takerTokenAmount: ZeroEx.toBaseUnitAmount(new BigNumber(200), 18),
}); });
const filledTakerTokenAmountBefore = const filledTakerTokenAmountBefore = await zeroEx.exchange.getFilledTakerAmountAsync(
await zeroEx.exchange.getFilledTakerAmountAsync(order.params.orderHashHex); order.params.orderHashHex,
);
expect(filledTakerTokenAmountBefore).to.be.bignumber.equal(0); expect(filledTakerTokenAmountBefore).to.be.bignumber.equal(0);
const fillTakerTokenAmount = order.params.takerTokenAmount.div(2); const fillTakerTokenAmount = order.params.takerTokenAmount.div(2);
await exWrapper.fillOrderAsync(order, taker, { fillTakerTokenAmount }); await exWrapper.fillOrderAsync(order, taker, { fillTakerTokenAmount });
const filledTakerTokenAmountAfter = const filledTakerTokenAmountAfter = await zeroEx.exchange.getFilledTakerAmountAsync(
await zeroEx.exchange.getFilledTakerAmountAsync(order.params.orderHashHex); order.params.orderHashHex,
);
expect(filledTakerTokenAmountAfter).to.be.bignumber.equal(fillTakerTokenAmount); expect(filledTakerTokenAmountAfter).to.be.bignumber.equal(fillTakerTokenAmount);
const newBalances = await dmyBalances.getAsync(); const newBalances = await dmyBalances.getAsync();
@ -268,20 +298,27 @@ contract('Exchange', (accounts: string[]) => {
const paidTakerFee = order.params.takerFee const paidTakerFee = order.params.takerFee
.times(fillMakerTokenAmount) .times(fillMakerTokenAmount)
.dividedToIntegerBy(order.params.makerTokenAmount); .dividedToIntegerBy(order.params.makerTokenAmount);
expect(newBalances[maker][order.params.makerToken]) expect(newBalances[maker][order.params.makerToken]).to.be.bignumber.equal(
.to.be.bignumber.equal(balances[maker][order.params.makerToken].minus(fillMakerTokenAmount)); balances[maker][order.params.makerToken].minus(fillMakerTokenAmount),
expect(newBalances[maker][order.params.takerToken]) );
.to.be.bignumber.equal(balances[maker][order.params.takerToken].add(fillTakerTokenAmount)); expect(newBalances[maker][order.params.takerToken]).to.be.bignumber.equal(
expect(newBalances[maker][zrx.address]).to.be.bignumber balances[maker][order.params.takerToken].add(fillTakerTokenAmount),
.equal(balances[maker][zrx.address].minus(paidMakerFee)); );
expect(newBalances[taker][order.params.takerToken]) expect(newBalances[maker][zrx.address]).to.be.bignumber.equal(
.to.be.bignumber.equal(balances[taker][order.params.takerToken].minus(fillTakerTokenAmount)); balances[maker][zrx.address].minus(paidMakerFee),
expect(newBalances[taker][order.params.makerToken]) );
.to.be.bignumber.equal(balances[taker][order.params.makerToken].add(fillMakerTokenAmount)); expect(newBalances[taker][order.params.takerToken]).to.be.bignumber.equal(
expect(newBalances[taker][zrx.address]).to.be.bignumber balances[taker][order.params.takerToken].minus(fillTakerTokenAmount),
.equal(balances[taker][zrx.address].minus(paidTakerFee)); );
expect(newBalances[feeRecipient][zrx.address]) expect(newBalances[taker][order.params.makerToken]).to.be.bignumber.equal(
.to.be.bignumber.equal(balances[feeRecipient][zrx.address].add(paidMakerFee.add(paidTakerFee))); balances[taker][order.params.makerToken].add(fillMakerTokenAmount),
);
expect(newBalances[taker][zrx.address]).to.be.bignumber.equal(
balances[taker][zrx.address].minus(paidTakerFee),
);
expect(newBalances[feeRecipient][zrx.address]).to.be.bignumber.equal(
balances[feeRecipient][zrx.address].add(paidMakerFee.add(paidTakerFee)),
);
}); });
it('should transfer the correct amounts when taker is specified and order is claimed by taker', async () => { it('should transfer the correct amounts when taker is specified and order is claimed by taker', async () => {
@ -291,15 +328,17 @@ contract('Exchange', (accounts: string[]) => {
takerTokenAmount: ZeroEx.toBaseUnitAmount(new BigNumber(200), 18), takerTokenAmount: ZeroEx.toBaseUnitAmount(new BigNumber(200), 18),
}); });
const filledTakerTokenAmountBefore = const filledTakerTokenAmountBefore = await zeroEx.exchange.getFilledTakerAmountAsync(
await zeroEx.exchange.getFilledTakerAmountAsync(order.params.orderHashHex); order.params.orderHashHex,
);
expect(filledTakerTokenAmountBefore).to.be.bignumber.equal(0); expect(filledTakerTokenAmountBefore).to.be.bignumber.equal(0);
const fillTakerTokenAmount = order.params.takerTokenAmount.div(2); const fillTakerTokenAmount = order.params.takerTokenAmount.div(2);
await exWrapper.fillOrderAsync(order, taker, { fillTakerTokenAmount }); await exWrapper.fillOrderAsync(order, taker, { fillTakerTokenAmount });
const filledTakerTokenAmountAfter = const filledTakerTokenAmountAfter = await zeroEx.exchange.getFilledTakerAmountAsync(
await zeroEx.exchange.getFilledTakerAmountAsync(order.params.orderHashHex); order.params.orderHashHex,
);
const expectedFillAmountTAfter = fillTakerTokenAmount.add(filledTakerTokenAmountBefore); const expectedFillAmountTAfter = fillTakerTokenAmount.add(filledTakerTokenAmountBefore);
expect(filledTakerTokenAmountAfter).to.be.bignumber.equal(expectedFillAmountTAfter); expect(filledTakerTokenAmountAfter).to.be.bignumber.equal(expectedFillAmountTAfter);
@ -314,55 +353,70 @@ contract('Exchange', (accounts: string[]) => {
const paidTakerFee = order.params.takerFee const paidTakerFee = order.params.takerFee
.times(fillMakerTokenAmount) .times(fillMakerTokenAmount)
.dividedToIntegerBy(order.params.makerTokenAmount); .dividedToIntegerBy(order.params.makerTokenAmount);
expect(newBalances[maker][order.params.makerToken]) expect(newBalances[maker][order.params.makerToken]).to.be.bignumber.equal(
.to.be.bignumber.equal(balances[maker][order.params.makerToken].minus(fillMakerTokenAmount)); balances[maker][order.params.makerToken].minus(fillMakerTokenAmount),
expect(newBalances[maker][order.params.takerToken]) );
.to.be.bignumber.equal(balances[maker][order.params.takerToken].add(fillTakerTokenAmount)); expect(newBalances[maker][order.params.takerToken]).to.be.bignumber.equal(
expect(newBalances[maker][zrx.address]).to.be.bignumber balances[maker][order.params.takerToken].add(fillTakerTokenAmount),
.equal(balances[maker][zrx.address].minus(paidMakerFee)); );
expect(newBalances[taker][order.params.takerToken]) expect(newBalances[maker][zrx.address]).to.be.bignumber.equal(
.to.be.bignumber.equal(balances[taker][order.params.takerToken].minus(fillTakerTokenAmount)); balances[maker][zrx.address].minus(paidMakerFee),
expect(newBalances[taker][order.params.makerToken]) );
.to.be.bignumber.equal(balances[taker][order.params.makerToken].add(fillMakerTokenAmount)); expect(newBalances[taker][order.params.takerToken]).to.be.bignumber.equal(
expect(newBalances[taker][zrx.address]).to.be.bignumber balances[taker][order.params.takerToken].minus(fillTakerTokenAmount),
.equal(balances[taker][zrx.address].minus(paidTakerFee)); );
expect(newBalances[feeRecipient][zrx.address]) expect(newBalances[taker][order.params.makerToken]).to.be.bignumber.equal(
.to.be.bignumber.equal(balances[feeRecipient][zrx.address].add(paidMakerFee.add(paidTakerFee))); balances[taker][order.params.makerToken].add(fillMakerTokenAmount),
);
expect(newBalances[taker][zrx.address]).to.be.bignumber.equal(
balances[taker][zrx.address].minus(paidTakerFee),
);
expect(newBalances[feeRecipient][zrx.address]).to.be.bignumber.equal(
balances[feeRecipient][zrx.address].add(paidMakerFee.add(paidTakerFee)),
);
}); });
it('should fill remaining value if fillTakerTokenAmount > remaining takerTokenAmount', async () => { it('should fill remaining value if fillTakerTokenAmount > remaining takerTokenAmount', async () => {
const fillTakerTokenAmount = order.params.takerTokenAmount.div(2); const fillTakerTokenAmount = order.params.takerTokenAmount.div(2);
await exWrapper.fillOrderAsync(order, taker, { fillTakerTokenAmount }); await exWrapper.fillOrderAsync(order, taker, { fillTakerTokenAmount });
const res = await exWrapper.fillOrderAsync(order, taker, const res = await exWrapper.fillOrderAsync(order, taker, {
{fillTakerTokenAmount: order.params.takerTokenAmount}); fillTakerTokenAmount: order.params.takerTokenAmount,
});
expect(res.logs[0].args.filledTakerTokenAmount) expect(res.logs[0].args.filledTakerTokenAmount).to.be.bignumber.equal(
.to.be.bignumber.equal(order.params.takerTokenAmount.minus(fillTakerTokenAmount)); order.params.takerTokenAmount.minus(fillTakerTokenAmount),
);
const newBalances = await dmyBalances.getAsync(); const newBalances = await dmyBalances.getAsync();
expect(newBalances[maker][order.params.makerToken]) expect(newBalances[maker][order.params.makerToken]).to.be.bignumber.equal(
.to.be.bignumber.equal(balances[maker][order.params.makerToken].minus(order.params.makerTokenAmount)); balances[maker][order.params.makerToken].minus(order.params.makerTokenAmount),
expect(newBalances[maker][order.params.takerToken]) );
.to.be.bignumber.equal(balances[maker][order.params.takerToken].add(order.params.takerTokenAmount)); expect(newBalances[maker][order.params.takerToken]).to.be.bignumber.equal(
expect(newBalances[maker][zrx.address]) balances[maker][order.params.takerToken].add(order.params.takerTokenAmount),
.to.be.bignumber.equal(balances[maker][zrx.address].minus(order.params.makerFee)); );
expect(newBalances[taker][order.params.takerToken]) expect(newBalances[maker][zrx.address]).to.be.bignumber.equal(
.to.be.bignumber.equal(balances[taker][order.params.takerToken].minus(order.params.takerTokenAmount)); balances[maker][zrx.address].minus(order.params.makerFee),
expect(newBalances[taker][order.params.makerToken]) );
.to.be.bignumber.equal(balances[taker][order.params.makerToken].add(order.params.makerTokenAmount)); expect(newBalances[taker][order.params.takerToken]).to.be.bignumber.equal(
expect(newBalances[taker][zrx.address]) balances[taker][order.params.takerToken].minus(order.params.takerTokenAmount),
.to.be.bignumber.equal(balances[taker][zrx.address].minus(order.params.takerFee)); );
expect(newBalances[feeRecipient][zrx.address]) expect(newBalances[taker][order.params.makerToken]).to.be.bignumber.equal(
.to.be.bignumber.equal( balances[taker][order.params.makerToken].add(order.params.makerTokenAmount),
);
expect(newBalances[taker][zrx.address]).to.be.bignumber.equal(
balances[taker][zrx.address].minus(order.params.takerFee),
);
expect(newBalances[feeRecipient][zrx.address]).to.be.bignumber.equal(
balances[feeRecipient][zrx.address].add(order.params.makerFee.add(order.params.takerFee)), balances[feeRecipient][zrx.address].add(order.params.makerFee.add(order.params.takerFee)),
); );
}); });
it('should log 1 event with the correct arguments when order has a feeRecipient', async () => { it('should log 1 event with the correct arguments when order has a feeRecipient', async () => {
const divisor = 2; const divisor = 2;
const res = await exWrapper.fillOrderAsync(order, taker, const res = await exWrapper.fillOrderAsync(order, taker, {
{fillTakerTokenAmount: order.params.takerTokenAmount.div(divisor)}); fillTakerTokenAmount: order.params.takerTokenAmount.div(divisor),
});
expect(res.logs).to.have.length(1); expect(res.logs).to.have.length(1);
const logArgs = res.logs[0].args; const logArgs = res.logs[0].args;
@ -391,8 +445,9 @@ contract('Exchange', (accounts: string[]) => {
feeRecipient: ZeroEx.NULL_ADDRESS, feeRecipient: ZeroEx.NULL_ADDRESS,
}); });
const divisor = 2; const divisor = 2;
const res = await exWrapper.fillOrderAsync(order, taker, const res = await exWrapper.fillOrderAsync(order, taker, {
{fillTakerTokenAmount: order.params.takerTokenAmount.div(divisor)}); fillTakerTokenAmount: order.params.takerTokenAmount.div(divisor),
});
expect(res.logs).to.have.length(1); expect(res.logs).to.have.length(1);
const logArgs = res.logs[0].args; const logArgs = res.logs[0].args;
@ -455,13 +510,15 @@ contract('Exchange', (accounts: string[]) => {
it('should throw if fillTakerTokenAmount is 0', async () => { it('should throw if fillTakerTokenAmount is 0', async () => {
order = await orderFactory.newSignedOrderAsync(); order = await orderFactory.newSignedOrderAsync();
return expect(exWrapper.fillOrderAsync(order, taker, {fillTakerTokenAmount: new BigNumber(0)})) return expect(
.to.be.rejectedWith(constants.REVERT); exWrapper.fillOrderAsync(order, taker, {
fillTakerTokenAmount: new BigNumber(0),
}),
).to.be.rejectedWith(constants.REVERT);
}); });
it('should not change balances if maker balances are too low to fill order and \ it('should not change balances if maker balances are too low to fill order and \
shouldThrowOnInsufficientBalanceOrAllowance = false', shouldThrowOnInsufficientBalanceOrAllowance = false', async () => {
async () => {
order = await orderFactory.newSignedOrderAsync({ order = await orderFactory.newSignedOrderAsync({
makerTokenAmount: ZeroEx.toBaseUnitAmount(new BigNumber(100000), 18), makerTokenAmount: ZeroEx.toBaseUnitAmount(new BigNumber(100000), 18),
}); });
@ -472,19 +529,20 @@ contract('Exchange', (accounts: string[]) => {
}); });
it('should throw if maker balances are too low to fill order and \ it('should throw if maker balances are too low to fill order and \
shouldThrowOnInsufficientBalanceOrAllowance = true', shouldThrowOnInsufficientBalanceOrAllowance = true', async () => {
async () => {
order = await orderFactory.newSignedOrderAsync({ order = await orderFactory.newSignedOrderAsync({
makerTokenAmount: ZeroEx.toBaseUnitAmount(new BigNumber(100000), 18), makerTokenAmount: ZeroEx.toBaseUnitAmount(new BigNumber(100000), 18),
}); });
return expect(exWrapper.fillOrderAsync(order, taker, {shouldThrowOnInsufficientBalanceOrAllowance: true})) return expect(
.to.be.rejectedWith(constants.REVERT); exWrapper.fillOrderAsync(order, taker, {
shouldThrowOnInsufficientBalanceOrAllowance: true,
}),
).to.be.rejectedWith(constants.REVERT);
}); });
it('should not change balances if taker balances are too low to fill order and \ it('should not change balances if taker balances are too low to fill order and \
shouldThrowOnInsufficientBalanceOrAllowance = false', shouldThrowOnInsufficientBalanceOrAllowance = false', async () => {
async () => {
order = await orderFactory.newSignedOrderAsync({ order = await orderFactory.newSignedOrderAsync({
takerTokenAmount: ZeroEx.toBaseUnitAmount(new BigNumber(100000), 18), takerTokenAmount: ZeroEx.toBaseUnitAmount(new BigNumber(100000), 18),
}); });
@ -495,59 +553,70 @@ contract('Exchange', (accounts: string[]) => {
}); });
it('should throw if taker balances are too low to fill order and \ it('should throw if taker balances are too low to fill order and \
shouldThrowOnInsufficientBalanceOrAllowance = true', shouldThrowOnInsufficientBalanceOrAllowance = true', async () => {
async () => {
order = await orderFactory.newSignedOrderAsync({ order = await orderFactory.newSignedOrderAsync({
takerTokenAmount: ZeroEx.toBaseUnitAmount(new BigNumber(100000), 18), takerTokenAmount: ZeroEx.toBaseUnitAmount(new BigNumber(100000), 18),
}); });
return expect(exWrapper.fillOrderAsync(order, taker, {shouldThrowOnInsufficientBalanceOrAllowance: true})) return expect(
.to.be.rejectedWith(constants.REVERT); exWrapper.fillOrderAsync(order, taker, {
shouldThrowOnInsufficientBalanceOrAllowance: true,
}),
).to.be.rejectedWith(constants.REVERT);
}); });
it('should not change balances if maker allowances are too low to fill order and \ it('should not change balances if maker allowances are too low to fill order and \
shouldThrowOnInsufficientBalanceOrAllowance = false', shouldThrowOnInsufficientBalanceOrAllowance = false', async () => {
async () => {
await rep.approve(TokenTransferProxy.address, 0, { from: maker }); await rep.approve(TokenTransferProxy.address, 0, { from: maker });
await exWrapper.fillOrderAsync(order, taker); await exWrapper.fillOrderAsync(order, taker);
await rep.approve(TokenTransferProxy.address, INITIAL_ALLOWANCE, {from: maker}); await rep.approve(TokenTransferProxy.address, INITIAL_ALLOWANCE, {
from: maker,
});
const newBalances = await dmyBalances.getAsync(); const newBalances = await dmyBalances.getAsync();
expect(newBalances).to.be.deep.equal(balances); expect(newBalances).to.be.deep.equal(balances);
}); });
it('should throw if maker allowances are too low to fill order and \ it('should throw if maker allowances are too low to fill order and \
shouldThrowOnInsufficientBalanceOrAllowance = true', shouldThrowOnInsufficientBalanceOrAllowance = true', async () => {
async () => {
await rep.approve(TokenTransferProxy.address, 0, { from: maker }); await rep.approve(TokenTransferProxy.address, 0, { from: maker });
expect(exWrapper.fillOrderAsync(order, taker, {shouldThrowOnInsufficientBalanceOrAllowance: true})) expect(
.to.be.rejectedWith(constants.REVERT); exWrapper.fillOrderAsync(order, taker, {
await rep.approve(TokenTransferProxy.address, INITIAL_ALLOWANCE, {from: maker}); shouldThrowOnInsufficientBalanceOrAllowance: true,
}),
).to.be.rejectedWith(constants.REVERT);
await rep.approve(TokenTransferProxy.address, INITIAL_ALLOWANCE, {
from: maker,
});
}); });
it('should not change balances if taker allowances are too low to fill order and \ it('should not change balances if taker allowances are too low to fill order and \
shouldThrowOnInsufficientBalanceOrAllowance = false', shouldThrowOnInsufficientBalanceOrAllowance = false', async () => {
async () => {
await dgd.approve(TokenTransferProxy.address, 0, { from: taker }); await dgd.approve(TokenTransferProxy.address, 0, { from: taker });
await exWrapper.fillOrderAsync(order, taker); await exWrapper.fillOrderAsync(order, taker);
await dgd.approve(TokenTransferProxy.address, INITIAL_ALLOWANCE, {from: taker}); await dgd.approve(TokenTransferProxy.address, INITIAL_ALLOWANCE, {
from: taker,
});
const newBalances = await dmyBalances.getAsync(); const newBalances = await dmyBalances.getAsync();
expect(newBalances).to.be.deep.equal(balances); expect(newBalances).to.be.deep.equal(balances);
}); });
it('should throw if taker allowances are too low to fill order and \ it('should throw if taker allowances are too low to fill order and \
shouldThrowOnInsufficientBalanceOrAllowance = true', shouldThrowOnInsufficientBalanceOrAllowance = true', async () => {
async () => {
await dgd.approve(TokenTransferProxy.address, 0, { from: taker }); await dgd.approve(TokenTransferProxy.address, 0, { from: taker });
expect(exWrapper.fillOrderAsync(order, taker, {shouldThrowOnInsufficientBalanceOrAllowance: true})) expect(
.to.be.rejectedWith(constants.REVERT); exWrapper.fillOrderAsync(order, taker, {
await dgd.approve(TokenTransferProxy.address, INITIAL_ALLOWANCE, {from: taker}); shouldThrowOnInsufficientBalanceOrAllowance: true,
}),
).to.be.rejectedWith(constants.REVERT);
await dgd.approve(TokenTransferProxy.address, INITIAL_ALLOWANCE, {
from: taker,
});
}); });
it('should not change balances if makerToken is ZRX, makerTokenAmount + makerFee > maker balance, \ it('should not change balances if makerToken is ZRX, makerTokenAmount + makerFee > maker balance, \
and shouldThrowOnInsufficientBalanceOrAllowance = false', and shouldThrowOnInsufficientBalanceOrAllowance = false', async () => {
async () => {
const makerZRXBalance = new BigNumber(balances[maker][zrx.address]); const makerZRXBalance = new BigNumber(balances[maker][zrx.address]);
order = await orderFactory.newSignedOrderAsync({ order = await orderFactory.newSignedOrderAsync({
makerToken: zrx.address, makerToken: zrx.address,
@ -560,8 +629,7 @@ contract('Exchange', (accounts: string[]) => {
}); });
it('should not change balances if makerToken is ZRX, makerTokenAmount + makerFee > maker allowance, \ it('should not change balances if makerToken is ZRX, makerTokenAmount + makerFee > maker allowance, \
and shouldThrowOnInsufficientBalanceOrAllowance = false', and shouldThrowOnInsufficientBalanceOrAllowance = false', async () => {
async () => {
const makerZRXAllowance = await zrx.allowance(maker, TokenTransferProxy.address); const makerZRXAllowance = await zrx.allowance(maker, TokenTransferProxy.address);
order = await orderFactory.newSignedOrderAsync({ order = await orderFactory.newSignedOrderAsync({
makerToken: zrx.address, makerToken: zrx.address,
@ -574,8 +642,7 @@ contract('Exchange', (accounts: string[]) => {
}); });
it('should not change balances if takerToken is ZRX, takerTokenAmount + takerFee > taker balance, \ it('should not change balances if takerToken is ZRX, takerTokenAmount + takerFee > taker balance, \
and shouldThrowOnInsufficientBalanceOrAllowance = false', and shouldThrowOnInsufficientBalanceOrAllowance = false', async () => {
async () => {
const takerZRXBalance = new BigNumber(balances[taker][zrx.address]); const takerZRXBalance = new BigNumber(balances[taker][zrx.address]);
order = await orderFactory.newSignedOrderAsync({ order = await orderFactory.newSignedOrderAsync({
takerToken: zrx.address, takerToken: zrx.address,
@ -588,8 +655,7 @@ contract('Exchange', (accounts: string[]) => {
}); });
it('should not change balances if takerToken is ZRX, takerTokenAmount + takerFee > taker allowance, \ it('should not change balances if takerToken is ZRX, takerTokenAmount + takerFee > taker allowance, \
and shouldThrowOnInsufficientBalanceOrAllowance = false', and shouldThrowOnInsufficientBalanceOrAllowance = false', async () => {
async () => {
const takerZRXAllowance = await zrx.allowance(taker, TokenTransferProxy.address); const takerZRXAllowance = await zrx.allowance(taker, TokenTransferProxy.address);
order = await orderFactory.newSignedOrderAsync({ order = await orderFactory.newSignedOrderAsync({
takerToken: zrx.address, takerToken: zrx.address,
@ -610,8 +676,11 @@ contract('Exchange', (accounts: string[]) => {
takerToken: maliciousToken.address, takerToken: maliciousToken.address,
}); });
return expect(exWrapper.fillOrderAsync(order, taker, {shouldThrowOnInsufficientBalanceOrAllowance: false})) return expect(
.to.be.rejectedWith(constants.REVERT); exWrapper.fillOrderAsync(order, taker, {
shouldThrowOnInsufficientBalanceOrAllowance: false,
}),
).to.be.rejectedWith(constants.REVERT);
}); });
it('should not change balances if an order is expired', async () => { it('should not change balances if an order is expired', async () => {
@ -674,13 +743,18 @@ contract('Exchange', (accounts: string[]) => {
it('should throw if cancelTakerTokenAmount is 0', async () => { it('should throw if cancelTakerTokenAmount is 0', async () => {
order = await orderFactory.newSignedOrderAsync(); order = await orderFactory.newSignedOrderAsync();
return expect(exWrapper.cancelOrderAsync(order, maker, {cancelTakerTokenAmount: new BigNumber(0)})) return expect(
.to.be.rejectedWith(constants.REVERT); exWrapper.cancelOrderAsync(order, maker, {
cancelTakerTokenAmount: new BigNumber(0),
}),
).to.be.rejectedWith(constants.REVERT);
}); });
it('should be able to cancel a full order', async () => { it('should be able to cancel a full order', async () => {
await exWrapper.cancelOrderAsync(order, maker); await exWrapper.cancelOrderAsync(order, maker);
await exWrapper.fillOrderAsync(order, taker, {fillTakerTokenAmount: order.params.takerTokenAmount.div(2)}); await exWrapper.fillOrderAsync(order, taker, {
fillTakerTokenAmount: order.params.takerTokenAmount.div(2),
});
const newBalances = await dmyBalances.getAsync(); const newBalances = await dmyBalances.getAsync();
expect(newBalances).to.be.deep.equal(balances); expect(newBalances).to.be.deep.equal(balances);
@ -688,12 +762,16 @@ contract('Exchange', (accounts: string[]) => {
it('should be able to cancel part of an order', async () => { it('should be able to cancel part of an order', async () => {
const cancelTakerTokenAmount = order.params.takerTokenAmount.div(2); const cancelTakerTokenAmount = order.params.takerTokenAmount.div(2);
await exWrapper.cancelOrderAsync(order, maker, {cancelTakerTokenAmount}); await exWrapper.cancelOrderAsync(order, maker, {
cancelTakerTokenAmount,
});
const res = await exWrapper.fillOrderAsync(order, taker, const res = await exWrapper.fillOrderAsync(order, taker, {
{fillTakerTokenAmount: order.params.takerTokenAmount}); fillTakerTokenAmount: order.params.takerTokenAmount,
expect(res.logs[0].args.filledTakerTokenAmount) });
.to.be.bignumber.equal(order.params.takerTokenAmount.minus(cancelTakerTokenAmount)); expect(res.logs[0].args.filledTakerTokenAmount).to.be.bignumber.equal(
order.params.takerTokenAmount.minus(cancelTakerTokenAmount),
);
const newBalances = await dmyBalances.getAsync(); const newBalances = await dmyBalances.getAsync();
const cancelMakerTokenAmount = cancelTakerTokenAmount const cancelMakerTokenAmount = cancelTakerTokenAmount
@ -705,26 +783,34 @@ contract('Exchange', (accounts: string[]) => {
const paidTakerFee = order.params.takerFee const paidTakerFee = order.params.takerFee
.times(cancelMakerTokenAmount) .times(cancelMakerTokenAmount)
.dividedToIntegerBy(order.params.makerTokenAmount); .dividedToIntegerBy(order.params.makerTokenAmount);
expect(newBalances[maker][order.params.makerToken]) expect(newBalances[maker][order.params.makerToken]).to.be.bignumber.equal(
.to.be.bignumber.equal(balances[maker][order.params.makerToken].minus(cancelMakerTokenAmount)); balances[maker][order.params.makerToken].minus(cancelMakerTokenAmount),
expect(newBalances[maker][order.params.takerToken]) );
.to.be.bignumber.equal(balances[maker][order.params.takerToken].add(cancelTakerTokenAmount)); expect(newBalances[maker][order.params.takerToken]).to.be.bignumber.equal(
expect(newBalances[maker][zrx.address]) balances[maker][order.params.takerToken].add(cancelTakerTokenAmount),
.to.be.bignumber.equal(balances[maker][zrx.address].minus(paidMakerFee)); );
expect(newBalances[taker][order.params.takerToken]) expect(newBalances[maker][zrx.address]).to.be.bignumber.equal(
.to.be.bignumber.equal(balances[taker][order.params.takerToken].minus(cancelTakerTokenAmount)); balances[maker][zrx.address].minus(paidMakerFee),
expect(newBalances[taker][order.params.makerToken]) );
.to.be.bignumber.equal(balances[taker][order.params.makerToken].add(cancelMakerTokenAmount)); expect(newBalances[taker][order.params.takerToken]).to.be.bignumber.equal(
expect(newBalances[taker][zrx.address]).to.be.bignumber balances[taker][order.params.takerToken].minus(cancelTakerTokenAmount),
.equal(balances[taker][zrx.address].minus(paidTakerFee)); );
expect(newBalances[feeRecipient][zrx.address]) expect(newBalances[taker][order.params.makerToken]).to.be.bignumber.equal(
.to.be.bignumber.equal(balances[feeRecipient][zrx.address].add(paidMakerFee.add(paidTakerFee))); balances[taker][order.params.makerToken].add(cancelMakerTokenAmount),
);
expect(newBalances[taker][zrx.address]).to.be.bignumber.equal(
balances[taker][zrx.address].minus(paidTakerFee),
);
expect(newBalances[feeRecipient][zrx.address]).to.be.bignumber.equal(
balances[feeRecipient][zrx.address].add(paidMakerFee.add(paidTakerFee)),
);
}); });
it('should log 1 event with correct arguments', async () => { it('should log 1 event with correct arguments', async () => {
const divisor = 2; const divisor = 2;
const res = await exWrapper.cancelOrderAsync(order, maker, const res = await exWrapper.cancelOrderAsync(order, maker, {
{cancelTakerTokenAmount: order.params.takerTokenAmount.div(divisor)}); cancelTakerTokenAmount: order.params.takerTokenAmount.div(divisor),
});
expect(res.logs).to.have.length(1); expect(res.logs).to.have.length(1);
const logArgs = res.logs[0].args; const logArgs = res.logs[0].args;

View File

@ -12,10 +12,7 @@ import {chaiSetup} from '../utils/chai_setup';
chaiSetup.configure(); chaiSetup.configure();
const expect = chai.expect; const expect = chai.expect;
const { const { Exchange, TokenRegistry } = new Artifacts(artifacts);
Exchange,
TokenRegistry,
} = new Artifacts(artifacts);
contract('Exchange', (accounts: string[]) => { contract('Exchange', (accounts: string[]) => {
const maker = accounts[0]; const maker = accounts[0];
@ -26,10 +23,7 @@ contract('Exchange', (accounts: string[]) => {
let orderFactory: OrderFactory; let orderFactory: OrderFactory;
before(async () => { before(async () => {
const [tokenRegistry, exchange] = await Promise.all([ const [tokenRegistry, exchange] = await Promise.all([TokenRegistry.deployed(), Exchange.deployed()]);
TokenRegistry.deployed(),
Exchange.deployed(),
]);
exchangeWrapper = new ExchangeWrapper(exchange); exchangeWrapper = new ExchangeWrapper(exchange);
const [repAddress, dgdAddress] = await Promise.all([ const [repAddress, dgdAddress] = await Promise.all([
tokenRegistry.getTokenAddressBySymbol('REP'), tokenRegistry.getTokenAddressBySymbol('REP'),

View File

@ -14,12 +14,7 @@ import {chaiSetup} from '../utils/chai_setup';
chaiSetup.configure(); chaiSetup.configure();
const expect = chai.expect; const expect = chai.expect;
const { const { Exchange, TokenTransferProxy, DummyToken, TokenRegistry } = new Artifacts(artifacts);
Exchange,
TokenTransferProxy,
DummyToken,
TokenRegistry,
} = new Artifacts(artifacts);
contract('Exchange', (accounts: string[]) => { contract('Exchange', (accounts: string[]) => {
const maker = accounts[0]; const maker = accounts[0];
@ -43,10 +38,7 @@ contract('Exchange', (accounts: string[]) => {
let orderFactory: OrderFactory; let orderFactory: OrderFactory;
before(async () => { before(async () => {
[tokenRegistry, exchange] = await Promise.all([ [tokenRegistry, exchange] = await Promise.all([TokenRegistry.deployed(), Exchange.deployed()]);
TokenRegistry.deployed(),
Exchange.deployed(),
]);
exWrapper = new ExchangeWrapper(exchange); exWrapper = new ExchangeWrapper(exchange);
const [repAddress, dgdAddress, zrxAddress] = await Promise.all([ const [repAddress, dgdAddress, zrxAddress] = await Promise.all([
tokenRegistry.getTokenAddressBySymbol('REP'), tokenRegistry.getTokenAddressBySymbol('REP'),
@ -100,7 +92,9 @@ contract('Exchange', (accounts: string[]) => {
takerTokenAmount: ZeroEx.toBaseUnitAmount(new BigNumber(200), 18), takerTokenAmount: ZeroEx.toBaseUnitAmount(new BigNumber(200), 18),
}); });
const fillTakerTokenAmount = order.params.takerTokenAmount.div(2); const fillTakerTokenAmount = order.params.takerTokenAmount.div(2);
await exWrapper.fillOrKillOrderAsync(order, taker, {fillTakerTokenAmount}); await exWrapper.fillOrKillOrderAsync(order, taker, {
fillTakerTokenAmount,
});
const newBalances = await dmyBalances.getAsync(); const newBalances = await dmyBalances.getAsync();
@ -113,18 +107,23 @@ contract('Exchange', (accounts: string[]) => {
const takerFee = order.params.takerFee const takerFee = order.params.takerFee
.times(fillMakerTokenAmount) .times(fillMakerTokenAmount)
.dividedToIntegerBy(order.params.makerTokenAmount); .dividedToIntegerBy(order.params.makerTokenAmount);
expect(newBalances[maker][order.params.makerToken]) expect(newBalances[maker][order.params.makerToken]).to.be.bignumber.equal(
.to.be.bignumber.equal(balances[maker][order.params.makerToken].minus(fillMakerTokenAmount)); balances[maker][order.params.makerToken].minus(fillMakerTokenAmount),
expect(newBalances[maker][order.params.takerToken]) );
.to.be.bignumber.equal(balances[maker][order.params.takerToken].add(fillTakerTokenAmount)); expect(newBalances[maker][order.params.takerToken]).to.be.bignumber.equal(
balances[maker][order.params.takerToken].add(fillTakerTokenAmount),
);
expect(newBalances[maker][zrx.address]).to.be.bignumber.equal(balances[maker][zrx.address].minus(makerFee)); expect(newBalances[maker][zrx.address]).to.be.bignumber.equal(balances[maker][zrx.address].minus(makerFee));
expect(newBalances[taker][order.params.takerToken]) expect(newBalances[taker][order.params.takerToken]).to.be.bignumber.equal(
.to.be.bignumber.equal(balances[taker][order.params.takerToken].minus(fillTakerTokenAmount)); balances[taker][order.params.takerToken].minus(fillTakerTokenAmount),
expect(newBalances[taker][order.params.makerToken]) );
.to.be.bignumber.equal(balances[taker][order.params.makerToken].add(fillMakerTokenAmount)); expect(newBalances[taker][order.params.makerToken]).to.be.bignumber.equal(
balances[taker][order.params.makerToken].add(fillMakerTokenAmount),
);
expect(newBalances[taker][zrx.address]).to.be.bignumber.equal(balances[taker][zrx.address].minus(takerFee)); expect(newBalances[taker][zrx.address]).to.be.bignumber.equal(balances[taker][zrx.address].minus(takerFee));
expect(newBalances[feeRecipient][zrx.address]) expect(newBalances[feeRecipient][zrx.address]).to.be.bignumber.equal(
.to.be.bignumber.equal(balances[feeRecipient][zrx.address].add(makerFee.add(takerFee))); balances[feeRecipient][zrx.address].add(makerFee.add(takerFee)),
);
}); });
it('should throw if an order is expired', async () => { it('should throw if an order is expired', async () => {
@ -132,18 +131,18 @@ contract('Exchange', (accounts: string[]) => {
expirationTimestampInSec: new BigNumber(Math.floor((Date.now() - 10000) / 1000)), expirationTimestampInSec: new BigNumber(Math.floor((Date.now() - 10000) / 1000)),
}); });
return expect(exWrapper.fillOrKillOrderAsync(order, taker)) return expect(exWrapper.fillOrKillOrderAsync(order, taker)).to.be.rejectedWith(constants.REVERT);
.to.be.rejectedWith(constants.REVERT);
}); });
it('should throw if entire fillTakerTokenAmount not filled', async () => { it('should throw if entire fillTakerTokenAmount not filled', async () => {
const order = await orderFactory.newSignedOrderAsync(); const order = await orderFactory.newSignedOrderAsync();
const from = taker; const from = taker;
await exWrapper.fillOrderAsync(order, from, {fillTakerTokenAmount: order.params.takerTokenAmount.div(2)}); await exWrapper.fillOrderAsync(order, from, {
fillTakerTokenAmount: order.params.takerTokenAmount.div(2),
});
return expect(exWrapper.fillOrKillOrderAsync(order, taker)) return expect(exWrapper.fillOrKillOrderAsync(order, taker)).to.be.rejectedWith(constants.REVERT);
.to.be.rejectedWith(constants.REVERT);
}); });
}); });
@ -181,11 +180,14 @@ contract('Exchange', (accounts: string[]) => {
balances[taker][makerToken] = balances[taker][makerToken].add(fillMakerTokenAmount); balances[taker][makerToken] = balances[taker][makerToken].add(fillMakerTokenAmount);
balances[taker][takerToken] = balances[taker][takerToken].minus(fillTakerTokenAmount); balances[taker][takerToken] = balances[taker][takerToken].minus(fillTakerTokenAmount);
balances[taker][zrx.address] = balances[taker][zrx.address].minus(takerFee); balances[taker][zrx.address] = balances[taker][zrx.address].minus(takerFee);
balances[feeRecipient][zrx.address] = balances[feeRecipient][zrx.address] = balances[feeRecipient][zrx.address].add(
balances[feeRecipient][zrx.address].add(makerFee.add(takerFee)); makerFee.add(takerFee),
);
}); });
await exWrapper.batchFillOrdersAsync(orders, taker, {fillTakerTokenAmounts}); await exWrapper.batchFillOrdersAsync(orders, taker, {
fillTakerTokenAmounts,
});
const newBalances = await dmyBalances.getAsync(); const newBalances = await dmyBalances.getAsync();
expect(newBalances).to.be.deep.equal(balances); expect(newBalances).to.be.deep.equal(balances);
@ -215,11 +217,14 @@ contract('Exchange', (accounts: string[]) => {
balances[taker][makerToken] = balances[taker][makerToken].add(fillMakerTokenAmount); balances[taker][makerToken] = balances[taker][makerToken].add(fillMakerTokenAmount);
balances[taker][takerToken] = balances[taker][takerToken].minus(fillTakerTokenAmount); balances[taker][takerToken] = balances[taker][takerToken].minus(fillTakerTokenAmount);
balances[taker][zrx.address] = balances[taker][zrx.address].minus(takerFee); balances[taker][zrx.address] = balances[taker][zrx.address].minus(takerFee);
balances[feeRecipient][zrx.address] = balances[feeRecipient][zrx.address] = balances[feeRecipient][zrx.address].add(
balances[feeRecipient][zrx.address].add(makerFee.add(takerFee)); makerFee.add(takerFee),
);
}); });
await exWrapper.batchFillOrKillOrdersAsync(orders, taker, {fillTakerTokenAmounts}); await exWrapper.batchFillOrKillOrdersAsync(orders, taker, {
fillTakerTokenAmounts,
});
const newBalances = await dmyBalances.getAsync(); const newBalances = await dmyBalances.getAsync();
expect(newBalances).to.be.deep.equal(balances); expect(newBalances).to.be.deep.equal(balances);
@ -234,57 +239,77 @@ contract('Exchange', (accounts: string[]) => {
await exWrapper.fillOrKillOrderAsync(orders[0], taker); await exWrapper.fillOrKillOrderAsync(orders[0], taker);
return expect(exWrapper.batchFillOrKillOrdersAsync(orders, taker, {fillTakerTokenAmounts})) return expect(
.to.be.rejectedWith(constants.REVERT); exWrapper.batchFillOrKillOrdersAsync(orders, taker, {
fillTakerTokenAmounts,
}),
).to.be.rejectedWith(constants.REVERT);
}); });
}); });
describe('fillOrdersUpTo', () => { describe('fillOrdersUpTo', () => {
it('should stop when the entire fillTakerTokenAmount is filled', async () => { it('should stop when the entire fillTakerTokenAmount is filled', async () => {
const fillTakerTokenAmount = const fillTakerTokenAmount = orders[0].params.takerTokenAmount.plus(
orders[0].params.takerTokenAmount.plus(orders[1].params.takerTokenAmount.div(2)); orders[1].params.takerTokenAmount.div(2),
await exWrapper.fillOrdersUpToAsync(orders, taker, {fillTakerTokenAmount}); );
await exWrapper.fillOrdersUpToAsync(orders, taker, {
fillTakerTokenAmount,
});
const newBalances = await dmyBalances.getAsync(); const newBalances = await dmyBalances.getAsync();
const fillMakerTokenAmount = orders[0].params.makerTokenAmount.add( const fillMakerTokenAmount = orders[0].params.makerTokenAmount.add(
orders[1].params.makerTokenAmount.dividedToIntegerBy(2)); orders[1].params.makerTokenAmount.dividedToIntegerBy(2),
);
const makerFee = orders[0].params.makerFee.add(orders[1].params.makerFee.dividedToIntegerBy(2)); const makerFee = orders[0].params.makerFee.add(orders[1].params.makerFee.dividedToIntegerBy(2));
const takerFee = orders[0].params.takerFee.add(orders[1].params.takerFee.dividedToIntegerBy(2)); const takerFee = orders[0].params.takerFee.add(orders[1].params.takerFee.dividedToIntegerBy(2));
expect(newBalances[maker][orders[0].params.makerToken]) expect(newBalances[maker][orders[0].params.makerToken]).to.be.bignumber.equal(
.to.be.bignumber.equal(balances[maker][orders[0].params.makerToken].minus(fillMakerTokenAmount)); balances[maker][orders[0].params.makerToken].minus(fillMakerTokenAmount),
expect(newBalances[maker][orders[0].params.takerToken]) );
.to.be.bignumber.equal(balances[maker][orders[0].params.takerToken].add(fillTakerTokenAmount)); expect(newBalances[maker][orders[0].params.takerToken]).to.be.bignumber.equal(
expect(newBalances[maker][zrx.address]).to.be.bignumber balances[maker][orders[0].params.takerToken].add(fillTakerTokenAmount),
.equal(balances[maker][zrx.address].minus(makerFee)); );
expect(newBalances[taker][orders[0].params.takerToken]) expect(newBalances[maker][zrx.address]).to.be.bignumber.equal(
.to.be.bignumber.equal(balances[taker][orders[0].params.takerToken].minus(fillTakerTokenAmount)); balances[maker][zrx.address].minus(makerFee),
expect(newBalances[taker][orders[0].params.makerToken]) );
.to.be.bignumber.equal(balances[taker][orders[0].params.makerToken].add(fillMakerTokenAmount)); expect(newBalances[taker][orders[0].params.takerToken]).to.be.bignumber.equal(
expect(newBalances[taker][zrx.address]).to.be.bignumber balances[taker][orders[0].params.takerToken].minus(fillTakerTokenAmount),
.equal(balances[taker][zrx.address].minus(takerFee)); );
expect(newBalances[feeRecipient][zrx.address]) expect(newBalances[taker][orders[0].params.makerToken]).to.be.bignumber.equal(
.to.be.bignumber.equal(balances[feeRecipient][zrx.address].add(makerFee.add(takerFee))); balances[taker][orders[0].params.makerToken].add(fillMakerTokenAmount),
);
expect(newBalances[taker][zrx.address]).to.be.bignumber.equal(
balances[taker][zrx.address].minus(takerFee),
);
expect(newBalances[feeRecipient][zrx.address]).to.be.bignumber.equal(
balances[feeRecipient][zrx.address].add(makerFee.add(takerFee)),
);
}); });
it('should fill all orders if cannot fill entire fillTakerTokenAmount', async () => { it('should fill all orders if cannot fill entire fillTakerTokenAmount', async () => {
const fillTakerTokenAmount = ZeroEx.toBaseUnitAmount(new BigNumber(100000), 18); const fillTakerTokenAmount = ZeroEx.toBaseUnitAmount(new BigNumber(100000), 18);
orders.forEach(order => { orders.forEach(order => {
balances[maker][order.params.makerToken] = balances[maker][order.params.makerToken] balances[maker][order.params.makerToken] = balances[maker][order.params.makerToken].minus(
.minus(order.params.makerTokenAmount); order.params.makerTokenAmount,
balances[maker][order.params.takerToken] = balances[maker][order.params.takerToken] );
.add(order.params.takerTokenAmount); balances[maker][order.params.takerToken] = balances[maker][order.params.takerToken].add(
balances[maker][zrx.address] = balances[maker][zrx.address] order.params.takerTokenAmount,
.minus(order.params.makerFee); );
balances[taker][order.params.makerToken] = balances[taker][order.params.makerToken] balances[maker][zrx.address] = balances[maker][zrx.address].minus(order.params.makerFee);
.add(order.params.makerTokenAmount); balances[taker][order.params.makerToken] = balances[taker][order.params.makerToken].add(
balances[taker][order.params.takerToken] = balances[taker][order.params.takerToken] order.params.makerTokenAmount,
.minus(order.params.takerTokenAmount); );
balances[taker][order.params.takerToken] = balances[taker][order.params.takerToken].minus(
order.params.takerTokenAmount,
);
balances[taker][zrx.address] = balances[taker][zrx.address].minus(order.params.takerFee); balances[taker][zrx.address] = balances[taker][zrx.address].minus(order.params.takerFee);
balances[feeRecipient][zrx.address] = balances[feeRecipient][zrx.address] = balances[feeRecipient][zrx.address].add(
balances[feeRecipient][zrx.address].add(order.params.makerFee.add(order.params.takerFee)); order.params.makerFee.add(order.params.takerFee),
);
});
await exWrapper.fillOrdersUpToAsync(orders, taker, {
fillTakerTokenAmount,
}); });
await exWrapper.fillOrdersUpToAsync(orders, taker, {fillTakerTokenAmount});
const newBalances = await dmyBalances.getAsync(); const newBalances = await dmyBalances.getAsync();
expect(newBalances).to.be.deep.equal(balances); expect(newBalances).to.be.deep.equal(balances);
@ -298,8 +323,9 @@ contract('Exchange', (accounts: string[]) => {
]); ]);
return expect( return expect(
exWrapper.fillOrdersUpToAsync( exWrapper.fillOrdersUpToAsync(orders, taker, {
orders, taker, {fillTakerTokenAmount: ZeroEx.toBaseUnitAmount(new BigNumber(1000), 18)}), fillTakerTokenAmount: ZeroEx.toBaseUnitAmount(new BigNumber(1000), 18),
}),
).to.be.rejectedWith(constants.REVERT); ).to.be.rejectedWith(constants.REVERT);
}); });
}); });
@ -307,10 +333,13 @@ contract('Exchange', (accounts: string[]) => {
describe('batchCancelOrders', () => { describe('batchCancelOrders', () => {
it('should be able to cancel multiple orders', async () => { it('should be able to cancel multiple orders', async () => {
const cancelTakerTokenAmounts = _.map(orders, order => order.params.takerTokenAmount); const cancelTakerTokenAmounts = _.map(orders, order => order.params.takerTokenAmount);
await exWrapper.batchCancelOrdersAsync(orders, maker, {cancelTakerTokenAmounts}); await exWrapper.batchCancelOrdersAsync(orders, maker, {
cancelTakerTokenAmounts,
});
await exWrapper.batchFillOrdersAsync( await exWrapper.batchFillOrdersAsync(orders, taker, {
orders, taker, {fillTakerTokenAmounts: cancelTakerTokenAmounts}); fillTakerTokenAmounts: cancelTakerTokenAmounts,
});
const newBalances = await dmyBalances.getAsync(); const newBalances = await dmyBalances.getAsync();
expect(balances).to.be.deep.equal(newBalances); expect(balances).to.be.deep.equal(newBalances);
}); });

View File

@ -45,8 +45,9 @@ contract('MultiSigWalletWithTimeLock', (accounts: string[]) => {
describe('changeTimeLock', () => { describe('changeTimeLock', () => {
it('should throw when not called by wallet', async () => { it('should throw when not called by wallet', async () => {
return expect(multiSig.changeTimeLock(SECONDS_TIME_LOCKED, {from: owners[0]})) return expect(multiSig.changeTimeLock(SECONDS_TIME_LOCKED, { from: owners[0] })).to.be.rejectedWith(
.to.be.rejectedWith(constants.REVERT); constants.REVERT,
);
}); });
it('should throw without enough confirmations', async () => { it('should throw without enough confirmations', async () => {
@ -96,7 +97,9 @@ contract('MultiSigWalletWithTimeLock', (accounts: string[]) => {
const subRes = await multiSigWrapper.submitTransactionAsync(destination, from, dataParams); const subRes = await multiSigWrapper.submitTransactionAsync(destination, from, dataParams);
txId = subRes.logs[0].args.transactionId.toNumber(); txId = subRes.logs[0].args.transactionId.toNumber();
const confRes = await multiSig.confirmTransaction(txId, {from: owners[1]}); const confRes = await multiSig.confirmTransaction(txId, {
from: owners[1],
});
expect(confRes.logs).to.have.length(2); expect(confRes.logs).to.have.length(2);
return expect(multiSig.executeTransaction(txId)).to.be.rejectedWith(constants.REVERT); return expect(multiSig.executeTransaction(txId)).to.be.rejectedWith(constants.REVERT);

View File

@ -20,8 +20,14 @@ contract('MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress', (accounts: s
const SECONDS_TIME_LOCKED = 1000000; const SECONDS_TIME_LOCKED = 1000000;
// initialize fake addresses // initialize fake addresses
const authorizedAddress = `0x${crypto.solSHA3([accounts[0]]).slice(0, 20).toString('hex')}`; const authorizedAddress = `0x${crypto
const unauthorizedAddress = `0x${crypto.solSHA3([accounts[1]]).slice(0, 20).toString('hex')}`; .solSHA3([accounts[0]])
.slice(0, 20)
.toString('hex')}`;
const unauthorizedAddress = `0x${crypto
.solSHA3([accounts[1]])
.slice(0, 20)
.toString('hex')}`;
let tokenTransferProxy: ContractInstance; let tokenTransferProxy: ContractInstance;
let multiSig: ContractInstance; let multiSig: ContractInstance;
@ -32,10 +38,18 @@ contract('MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress', (accounts: s
beforeEach(async () => { beforeEach(async () => {
const initialOwner = accounts[0]; const initialOwner = accounts[0];
tokenTransferProxy = await TokenTransferProxy.new({ from: initialOwner }); tokenTransferProxy = await TokenTransferProxy.new({ from: initialOwner });
await tokenTransferProxy.addAuthorizedAddress(authorizedAddress, {from: initialOwner}); await tokenTransferProxy.addAuthorizedAddress(authorizedAddress, {
from: initialOwner,
});
multiSig = await MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress.new( multiSig = await MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress.new(
owners, requiredApprovals, SECONDS_TIME_LOCKED, tokenTransferProxy.address); owners,
await tokenTransferProxy.transferOwnership(multiSig.address, {from: initialOwner}); requiredApprovals,
SECONDS_TIME_LOCKED,
tokenTransferProxy.address,
);
await tokenTransferProxy.transferOwnership(multiSig.address, {
from: initialOwner,
});
multiSigWrapper = new MultiSigWrapper(multiSig); multiSigWrapper = new MultiSigWrapper(multiSig);
validDestination = tokenTransferProxy.address; validDestination = tokenTransferProxy.address;
}); });
@ -43,8 +57,7 @@ contract('MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress', (accounts: s
describe('isFunctionRemoveAuthorizedAddress', () => { describe('isFunctionRemoveAuthorizedAddress', () => {
it('should throw if data is not for removeAuthorizedAddress', async () => { it('should throw if data is not for removeAuthorizedAddress', async () => {
const data = MultiSigWrapper.encodeFnArgs('addAuthorizedAddress', PROXY_ABI, [owners[0]]); const data = MultiSigWrapper.encodeFnArgs('addAuthorizedAddress', PROXY_ABI, [owners[0]]);
return expect(multiSig.isFunctionRemoveAuthorizedAddress.call(data)) return expect(multiSig.isFunctionRemoveAuthorizedAddress.call(data)).to.be.rejectedWith(constants.REVERT);
.to.be.rejectedWith(constants.REVERT);
}); });
it('should return true if data is for removeAuthorizedAddress', async () => { it('should return true if data is for removeAuthorizedAddress', async () => {

View File

@ -81,16 +81,20 @@ contract('TokenRegistry', (accounts: string[]) => {
await tokenRegWrapper.addTokenAsync(token1, owner); await tokenRegWrapper.addTokenAsync(token1, owner);
const duplicateNameToken = _.assign({}, token2, { name: token1.name }); const duplicateNameToken = _.assign({}, token2, { name: token1.name });
return expect(tokenRegWrapper.addTokenAsync(duplicateNameToken, owner)) return expect(tokenRegWrapper.addTokenAsync(duplicateNameToken, owner)).to.be.rejectedWith(
.to.be.rejectedWith(constants.REVERT); constants.REVERT,
);
}); });
it('should throw if symbol already exists', async () => { it('should throw if symbol already exists', async () => {
await tokenRegWrapper.addTokenAsync(token1, owner); await tokenRegWrapper.addTokenAsync(token1, owner);
const duplicateSymbolToken = _.assign({}, token2, {symbol: token1.symbol}); const duplicateSymbolToken = _.assign({}, token2, {
symbol: token1.symbol,
});
return expect(tokenRegWrapper.addTokenAsync(duplicateSymbolToken, owner)) return expect(tokenRegWrapper.addTokenAsync(duplicateSymbolToken, owner)).to.be.rejectedWith(
.to.be.rejectedWith(constants.REVERT); constants.REVERT,
);
}); });
}); });
@ -115,12 +119,15 @@ contract('TokenRegistry', (accounts: string[]) => {
describe('setTokenName', () => { describe('setTokenName', () => {
it('should throw when not called by owner', async () => { it('should throw when not called by owner', async () => {
return expect(tokenReg.setTokenName(token1.address, token2.name, {from: notOwner})) return expect(
.to.be.rejectedWith(constants.REVERT); tokenReg.setTokenName(token1.address, token2.name, { from: notOwner }),
).to.be.rejectedWith(constants.REVERT);
}); });
it('should change the token name when called by owner', async () => { it('should change the token name when called by owner', async () => {
const res = await tokenReg.setTokenName(token1.address, token2.name, {from: owner}); const res = await tokenReg.setTokenName(token1.address, token2.name, {
from: owner,
});
expect(res.logs).to.have.length(1); expect(res.logs).to.have.length(1);
const [newData, oldData] = await Promise.all([ const [newData, oldData] = await Promise.all([
tokenRegWrapper.getTokenByNameAsync(token2.name), tokenRegWrapper.getTokenByNameAsync(token2.name),
@ -136,20 +143,25 @@ contract('TokenRegistry', (accounts: string[]) => {
it('should throw if the name already exists', async () => { it('should throw if the name already exists', async () => {
await tokenRegWrapper.addTokenAsync(token2, owner); await tokenRegWrapper.addTokenAsync(token2, owner);
return expect(tokenReg.setTokenName(token1.address, token2.name, {from: owner})) return expect(tokenReg.setTokenName(token1.address, token2.name, { from: owner })).to.be.rejectedWith(
.to.be.rejectedWith(constants.REVERT); constants.REVERT,
);
}); });
it('should throw if token does not exist', async () => { it('should throw if token does not exist', async () => {
return expect(tokenReg.setTokenName(nullToken.address, token2.name, {from: owner})) return expect(
.to.be.rejectedWith(constants.REVERT); tokenReg.setTokenName(nullToken.address, token2.name, { from: owner }),
).to.be.rejectedWith(constants.REVERT);
}); });
}); });
describe('setTokenSymbol', () => { describe('setTokenSymbol', () => {
it('should throw when not called by owner', async () => { it('should throw when not called by owner', async () => {
return expect(tokenReg.setTokenSymbol(token1.address, token2.symbol, {from: notOwner})) return expect(
.to.be.rejectedWith(constants.REVERT); tokenReg.setTokenSymbol(token1.address, token2.symbol, {
from: notOwner,
}),
).to.be.rejectedWith(constants.REVERT);
}); });
it('should change the token symbol when called by owner', async () => { it('should change the token symbol when called by owner', async () => {
@ -169,26 +181,35 @@ contract('TokenRegistry', (accounts: string[]) => {
it('should throw if the symbol already exists', async () => { it('should throw if the symbol already exists', async () => {
await tokenRegWrapper.addTokenAsync(token2, owner); await tokenRegWrapper.addTokenAsync(token2, owner);
return expect(tokenReg.setTokenSymbol(token1.address, token2.symbol, {from: owner})) return expect(
.to.be.rejectedWith(constants.REVERT); tokenReg.setTokenSymbol(token1.address, token2.symbol, {
from: owner,
}),
).to.be.rejectedWith(constants.REVERT);
}); });
it('should throw if token does not exist', async () => { it('should throw if token does not exist', async () => {
return expect(tokenReg.setTokenSymbol(nullToken.address, token2.symbol, {from: owner})) return expect(
.to.be.rejectedWith(constants.REVERT); tokenReg.setTokenSymbol(nullToken.address, token2.symbol, {
from: owner,
}),
).to.be.rejectedWith(constants.REVERT);
}); });
}); });
describe('removeToken', () => { describe('removeToken', () => {
it('should throw if not called by owner', async () => { it('should throw if not called by owner', async () => {
const index = 0; const index = 0;
return expect(tokenReg.removeToken(token1.address, index, {from: notOwner})) return expect(tokenReg.removeToken(token1.address, index, { from: notOwner })).to.be.rejectedWith(
.to.be.rejectedWith(constants.REVERT); constants.REVERT,
);
}); });
it('should remove token metadata when called by owner', async () => { it('should remove token metadata when called by owner', async () => {
const index = 0; const index = 0;
const res = await tokenReg.removeToken(token1.address, index, {from: owner}); const res = await tokenReg.removeToken(token1.address, index, {
from: owner,
});
expect(res.logs).to.have.length(1); expect(res.logs).to.have.length(1);
const tokenData = await tokenRegWrapper.getTokenMetaDataAsync(token1.address); const tokenData = await tokenRegWrapper.getTokenMetaDataAsync(token1.address);
expect(tokenData).to.be.deep.equal(nullToken); expect(tokenData).to.be.deep.equal(nullToken);
@ -196,17 +217,18 @@ contract('TokenRegistry', (accounts: string[]) => {
it('should throw if token does not exist', async () => { it('should throw if token does not exist', async () => {
const index = 0; const index = 0;
return expect(tokenReg.removeToken(nullToken.address, index, {from: owner})) return expect(tokenReg.removeToken(nullToken.address, index, { from: owner })).to.be.rejectedWith(
.to.be.rejectedWith(constants.REVERT); constants.REVERT,
);
}); });
it('should throw if token at given index does not match address', async () => { it('should throw if token at given index does not match address', async () => {
await tokenRegWrapper.addTokenAsync(token2, owner); await tokenRegWrapper.addTokenAsync(token2, owner);
const incorrectIndex = 0; const incorrectIndex = 0;
return expect(tokenReg.removeToken(token2.address, incorrectIndex, {from: owner})) return expect(tokenReg.removeToken(token2.address, incorrectIndex, { from: owner })).to.be.rejectedWith(
.to.be.rejectedWith(constants.REVERT); constants.REVERT,
}); );
});
}); });
}); });
}); });

View File

@ -22,12 +22,15 @@ contract('TokenTransferProxy', (accounts: string[]) => {
describe('addAuthorizedAddress', () => { describe('addAuthorizedAddress', () => {
it('should throw if not called by owner', async () => { it('should throw if not called by owner', async () => {
return expect(tokenTransferProxy.addAuthorizedAddress(notOwner, {from: notOwner})) return expect(tokenTransferProxy.addAuthorizedAddress(notOwner, { from: notOwner })).to.be.rejectedWith(
.to.be.rejectedWith(constants.REVERT); constants.REVERT,
);
}); });
it('should allow owner to add an authorized address', async () => { it('should allow owner to add an authorized address', async () => {
await tokenTransferProxy.addAuthorizedAddress(notAuthorized, {from: owner}); await tokenTransferProxy.addAuthorizedAddress(notAuthorized, {
from: owner,
});
authorized = notAuthorized; authorized = notAuthorized;
notAuthorized = null; notAuthorized = null;
const isAuthorized = await tokenTransferProxy.authorized.call(authorized); const isAuthorized = await tokenTransferProxy.authorized.call(authorized);
@ -35,19 +38,25 @@ contract('TokenTransferProxy', (accounts: string[]) => {
}); });
it('should throw if owner attempts to authorize a duplicate address', async () => { it('should throw if owner attempts to authorize a duplicate address', async () => {
return expect(tokenTransferProxy.addAuthorizedAddress(authorized, {from: owner})) return expect(tokenTransferProxy.addAuthorizedAddress(authorized, { from: owner })).to.be.rejectedWith(
.to.be.rejectedWith(constants.REVERT); constants.REVERT,
);
}); });
}); });
describe('removeAuthorizedAddress', () => { describe('removeAuthorizedAddress', () => {
it('should throw if not called by owner', async () => { it('should throw if not called by owner', async () => {
return expect(tokenTransferProxy.removeAuthorizedAddress(authorized, {from: notOwner})) return expect(
.to.be.rejectedWith(constants.REVERT); tokenTransferProxy.removeAuthorizedAddress(authorized, {
from: notOwner,
}),
).to.be.rejectedWith(constants.REVERT);
}); });
it('should allow owner to remove an authorized address', async () => { it('should allow owner to remove an authorized address', async () => {
await tokenTransferProxy.removeAuthorizedAddress(authorized, {from: owner}); await tokenTransferProxy.removeAuthorizedAddress(authorized, {
from: owner,
});
notAuthorized = authorized; notAuthorized = authorized;
authorized = null; authorized = null;
@ -56,8 +65,11 @@ contract('TokenTransferProxy', (accounts: string[]) => {
}); });
it('should throw if owner attempts to remove an address that is not authorized', async () => { it('should throw if owner attempts to remove an address that is not authorized', async () => {
return expect(tokenTransferProxy.removeAuthorizedAddress(notAuthorized, {from: owner})) return expect(
.to.be.rejectedWith(constants.REVERT); tokenTransferProxy.removeAuthorizedAddress(notAuthorized, {
from: owner,
}),
).to.be.rejectedWith(constants.REVERT);
}); });
}); });
@ -65,7 +77,9 @@ contract('TokenTransferProxy', (accounts: string[]) => {
it('should return all authorized addresses', async () => { it('should return all authorized addresses', async () => {
const initial = await tokenTransferProxy.getAuthorizedAddresses(); const initial = await tokenTransferProxy.getAuthorizedAddresses();
expect(initial).to.have.length(1); expect(initial).to.have.length(1);
await tokenTransferProxy.addAuthorizedAddress(notAuthorized, {from: owner}); await tokenTransferProxy.addAuthorizedAddress(notAuthorized, {
from: owner,
});
authorized = notAuthorized; authorized = notAuthorized;
notAuthorized = null; notAuthorized = null;
@ -73,7 +87,9 @@ contract('TokenTransferProxy', (accounts: string[]) => {
expect(afterAdd).to.have.length(2); expect(afterAdd).to.have.length(2);
expect(afterAdd).to.include(authorized); expect(afterAdd).to.include(authorized);
await tokenTransferProxy.removeAuthorizedAddress(authorized, {from: owner}); await tokenTransferProxy.removeAuthorizedAddress(authorized, {
from: owner,
});
notAuthorized = authorized; notAuthorized = authorized;
authorized = null; authorized = null;
const afterRemove = await tokenTransferProxy.getAuthorizedAddresses(); const afterRemove = await tokenTransferProxy.getAuthorizedAddresses();

View File

@ -8,11 +8,7 @@ import {chaiSetup} from '../utils/chai_setup';
chaiSetup.configure(); chaiSetup.configure();
const expect = chai.expect; const expect = chai.expect;
const { const { TokenTransferProxy, DummyToken, TokenRegistry } = new Artifacts(artifacts);
TokenTransferProxy,
DummyToken,
TokenRegistry,
} = new Artifacts(artifacts);
contract('TokenTransferProxy', (accounts: string[]) => { contract('TokenTransferProxy', (accounts: string[]) => {
const INIT_BAL = 100000000; const INIT_BAL = 100000000;
@ -36,32 +32,42 @@ contract('TokenTransferProxy', (accounts: string[]) => {
dmyBalances = new Balances([rep], [accounts[0], accounts[1]]); dmyBalances = new Balances([rep], [accounts[0], accounts[1]]);
await Promise.all([ await Promise.all([
rep.approve(TokenTransferProxy.address, INIT_ALLOW, {from: accounts[0]}), rep.approve(TokenTransferProxy.address, INIT_ALLOW, {
from: accounts[0],
}),
rep.setBalance(accounts[0], INIT_BAL, { from: owner }), rep.setBalance(accounts[0], INIT_BAL, { from: owner }),
rep.approve(TokenTransferProxy.address, INIT_ALLOW, {from: accounts[1]}), rep.approve(TokenTransferProxy.address, INIT_ALLOW, {
from: accounts[1],
}),
rep.setBalance(accounts[1], INIT_BAL, { from: owner }), rep.setBalance(accounts[1], INIT_BAL, { from: owner }),
]); ]);
}); });
describe('transferFrom', () => { describe('transferFrom', () => {
it('should throw when called by an unauthorized address', async () => { it('should throw when called by an unauthorized address', async () => {
expect(tokenTransferProxy.transferFrom(rep.address, accounts[0], accounts[1], 1000, {from: notAuthorized})) expect(
.to.be.rejectedWith(constants.REVERT); tokenTransferProxy.transferFrom(rep.address, accounts[0], accounts[1], 1000, { from: notAuthorized }),
).to.be.rejectedWith(constants.REVERT);
}); });
it('should allow an authorized address to transfer', async () => { it('should allow an authorized address to transfer', async () => {
const balances = await dmyBalances.getAsync(); const balances = await dmyBalances.getAsync();
await tokenTransferProxy.addAuthorizedAddress(notAuthorized, {from: owner}); await tokenTransferProxy.addAuthorizedAddress(notAuthorized, {
from: owner,
});
const transferAmt = 10000; const transferAmt = 10000;
await tokenTransferProxy.transferFrom(rep.address, accounts[0], accounts[1], await tokenTransferProxy.transferFrom(rep.address, accounts[0], accounts[1], transferAmt, {
transferAmt, {from: notAuthorized}); from: notAuthorized,
});
const newBalances = await dmyBalances.getAsync(); const newBalances = await dmyBalances.getAsync();
expect(newBalances[accounts[0]][rep.address]) expect(newBalances[accounts[0]][rep.address]).to.be.bignumber.equal(
.to.be.bignumber.equal(balances[accounts[0]][rep.address].minus(transferAmt)); balances[accounts[0]][rep.address].minus(transferAmt),
expect(newBalances[accounts[1]][rep.address]) );
.to.be.bignumber.equal(balances[accounts[1]][rep.address].add(transferAmt)); expect(newBalances[accounts[1]][rep.address]).to.be.bignumber.equal(
balances[accounts[1]][rep.address].add(transferAmt),
);
}); });
}); });
}); });

View File

@ -48,7 +48,9 @@ contract('UnlimitedAllowanceToken', (accounts: string[]) => {
}); });
it('should return true on a 0 value transfer', async () => { it('should return true on a 0 value transfer', async () => {
const didReturnTrue = await token.transfer.call(spender, 0, {from: owner}); const didReturnTrue = await token.transfer.call(spender, 0, {
from: owner,
});
expect(didReturnTrue).to.be.true(); expect(didReturnTrue).to.be.true();
}); });
}); });

View File

@ -36,8 +36,9 @@ contract('UnlimitedAllowanceTokenV2', (accounts: string[]) => {
it('should throw if owner has insufficient balance', async () => { it('should throw if owner has insufficient balance', async () => {
const ownerBalance = await zeroEx.token.getBalanceAsync(tokenAddress, owner); const ownerBalance = await zeroEx.token.getBalanceAsync(tokenAddress, owner);
const amountToTransfer = ownerBalance.plus(1); const amountToTransfer = ownerBalance.plus(1);
return expect(token.transfer.call(spender, amountToTransfer, {from: owner})) return expect(token.transfer.call(spender, amountToTransfer, { from: owner })).to.be.rejectedWith(
.to.be.rejectedWith(constants.REVERT); constants.REVERT,
);
}); });
it('should transfer balance from sender to receiver', async () => { it('should transfer balance from sender to receiver', async () => {
@ -55,7 +56,9 @@ contract('UnlimitedAllowanceTokenV2', (accounts: string[]) => {
}); });
it('should return true on a 0 value transfer', async () => { it('should return true on a 0 value transfer', async () => {
const didReturnTrue = await token.transfer.call(spender, 0, {from: owner}); const didReturnTrue = await token.transfer.call(spender, 0, {
from: owner,
});
expect(didReturnTrue).to.be.true(); expect(didReturnTrue).to.be.true();
}); });
}); });
@ -65,8 +68,11 @@ contract('UnlimitedAllowanceTokenV2', (accounts: string[]) => {
const ownerBalance = await zeroEx.token.getBalanceAsync(tokenAddress, owner); const ownerBalance = await zeroEx.token.getBalanceAsync(tokenAddress, owner);
const amountToTransfer = ownerBalance.plus(1); const amountToTransfer = ownerBalance.plus(1);
await zeroEx.token.setAllowanceAsync(tokenAddress, owner, spender, amountToTransfer); await zeroEx.token.setAllowanceAsync(tokenAddress, owner, spender, amountToTransfer);
return expect(token.transferFrom.call(owner, spender, amountToTransfer, {from: spender})) return expect(
.to.be.rejectedWith(constants.REVERT); token.transferFrom.call(owner, spender, amountToTransfer, {
from: spender,
}),
).to.be.rejectedWith(constants.REVERT);
}); });
it('should throw if spender has insufficient allowance', async () => { it('should throw if spender has insufficient allowance', async () => {
@ -77,8 +83,11 @@ contract('UnlimitedAllowanceTokenV2', (accounts: string[]) => {
const spenderAllowanceIsInsufficient = spenderAllowance.cmp(amountToTransfer) < 0; const spenderAllowanceIsInsufficient = spenderAllowance.cmp(amountToTransfer) < 0;
expect(spenderAllowanceIsInsufficient).to.be.true(); expect(spenderAllowanceIsInsufficient).to.be.true();
return expect(token.transferFrom.call(owner, spender, amountToTransfer, {from: spender})) return expect(
.to.be.rejectedWith(constants.REVERT); token.transferFrom.call(owner, spender, amountToTransfer, {
from: spender,
}),
).to.be.rejectedWith(constants.REVERT);
}); });
it('should return true on a 0 value transfer', async () => { it('should return true on a 0 value transfer', async () => {

View File

@ -85,7 +85,9 @@ contract('ZRXToken', (accounts: string[]) => {
}); });
it('should return true on a 0 value transfer', async () => { it('should return true on a 0 value transfer', async () => {
const didReturnTrue = await zrx.transfer.call(spender, 0, {from: owner}); const didReturnTrue = await zrx.transfer.call(spender, 0, {
from: owner,
});
expect(didReturnTrue).to.be.true(); expect(didReturnTrue).to.be.true();
}); });
}); });

View File

@ -21,7 +21,8 @@ export class Artifacts {
this.DummyTokenV2 = artifacts.require('DummyToken_v2'); this.DummyTokenV2 = artifacts.require('DummyToken_v2');
this.EtherToken = artifacts.require('WETH9'); this.EtherToken = artifacts.require('WETH9');
this.MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress = artifacts.require( this.MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress = artifacts.require(
'MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress'); 'MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress',
);
this.MaliciousToken = artifacts.require('MaliciousToken'); this.MaliciousToken = artifacts.require('MaliciousToken');
} }
} }

View File

@ -18,7 +18,7 @@ export const crypto = {
const isNumber = _.isFinite(arg); const isNumber = _.isFinite(arg);
if (isNumber) { if (isNumber) {
argTypes.push('uint8'); argTypes.push('uint8');
} else if ((arg).isBigNumber) { } else if (arg.isBigNumber) {
argTypes.push('uint256'); argTypes.push('uint256');
args[i] = new BN(arg.toString(10), 10); args[i] = new BN(arg.toString(10), 10);
} else if (ethUtil.isValidAddress(arg)) { } else if (ethUtil.isValidAddress(arg)) {

View File

@ -10,11 +10,14 @@ export class ExchangeWrapper {
constructor(exchangeContractInstance: ContractInstance) { constructor(exchangeContractInstance: ContractInstance) {
this._exchange = exchangeContractInstance; this._exchange = exchangeContractInstance;
} }
public async fillOrderAsync(order: Order, from: string, public async fillOrderAsync(
order: Order,
from: string,
opts: { opts: {
fillTakerTokenAmount?: BigNumber; fillTakerTokenAmount?: BigNumber;
shouldThrowOnInsufficientBalanceOrAllowance?: boolean; shouldThrowOnInsufficientBalanceOrAllowance?: boolean;
} = {}) { } = {},
) {
const shouldThrowOnInsufficientBalanceOrAllowance = !!opts.shouldThrowOnInsufficientBalanceOrAllowance; const shouldThrowOnInsufficientBalanceOrAllowance = !!opts.shouldThrowOnInsufficientBalanceOrAllowance;
const params = order.createFill(shouldThrowOnInsufficientBalanceOrAllowance, opts.fillTakerTokenAmount); const params = order.createFill(shouldThrowOnInsufficientBalanceOrAllowance, opts.fillTakerTokenAmount);
const tx = await this._exchange.fillOrder( const tx = await this._exchange.fillOrder(
@ -30,8 +33,7 @@ export class ExchangeWrapper {
_.each(tx.logs, log => wrapLogBigNumbers(log)); _.each(tx.logs, log => wrapLogBigNumbers(log));
return tx; return tx;
} }
public async cancelOrderAsync(order: Order, from: string, public async cancelOrderAsync(order: Order, from: string, opts: { cancelTakerTokenAmount?: BigNumber } = {}) {
opts: {cancelTakerTokenAmount?: BigNumber} = {}) {
const params = order.createCancel(opts.cancelTakerTokenAmount); const params = order.createCancel(opts.cancelTakerTokenAmount);
const tx = await this._exchange.cancelOrder( const tx = await this._exchange.cancelOrder(
params.orderAddresses, params.orderAddresses,
@ -42,8 +44,7 @@ export class ExchangeWrapper {
_.each(tx.logs, log => wrapLogBigNumbers(log)); _.each(tx.logs, log => wrapLogBigNumbers(log));
return tx; return tx;
} }
public async fillOrKillOrderAsync(order: Order, from: string, public async fillOrKillOrderAsync(order: Order, from: string, opts: { fillTakerTokenAmount?: BigNumber } = {}) {
opts: {fillTakerTokenAmount?: BigNumber} = {}) {
const shouldThrowOnInsufficientBalanceOrAllowance = true; const shouldThrowOnInsufficientBalanceOrAllowance = true;
const params = order.createFill(shouldThrowOnInsufficientBalanceOrAllowance, opts.fillTakerTokenAmount); const params = order.createFill(shouldThrowOnInsufficientBalanceOrAllowance, opts.fillTakerTokenAmount);
const tx = await this._exchange.fillOrKillOrder( const tx = await this._exchange.fillOrKillOrder(
@ -58,14 +59,20 @@ export class ExchangeWrapper {
_.each(tx.logs, log => wrapLogBigNumbers(log)); _.each(tx.logs, log => wrapLogBigNumbers(log));
return tx; return tx;
} }
public async batchFillOrdersAsync(orders: Order[], from: string, public async batchFillOrdersAsync(
orders: Order[],
from: string,
opts: { opts: {
fillTakerTokenAmounts?: BigNumber[]; fillTakerTokenAmounts?: BigNumber[];
shouldThrowOnInsufficientBalanceOrAllowance?: boolean; shouldThrowOnInsufficientBalanceOrAllowance?: boolean;
} = {}) { } = {},
) {
const shouldThrowOnInsufficientBalanceOrAllowance = !!opts.shouldThrowOnInsufficientBalanceOrAllowance; const shouldThrowOnInsufficientBalanceOrAllowance = !!opts.shouldThrowOnInsufficientBalanceOrAllowance;
const params = formatters.createBatchFill( const params = formatters.createBatchFill(
orders, shouldThrowOnInsufficientBalanceOrAllowance, opts.fillTakerTokenAmounts); orders,
shouldThrowOnInsufficientBalanceOrAllowance,
opts.fillTakerTokenAmounts,
);
const tx = await this._exchange.batchFillOrders( const tx = await this._exchange.batchFillOrders(
params.orderAddresses, params.orderAddresses,
params.orderValues, params.orderValues,
@ -79,8 +86,11 @@ export class ExchangeWrapper {
_.each(tx.logs, log => wrapLogBigNumbers(log)); _.each(tx.logs, log => wrapLogBigNumbers(log));
return tx; return tx;
} }
public async batchFillOrKillOrdersAsync(orders: Order[], from: string, public async batchFillOrKillOrdersAsync(
opts: {fillTakerTokenAmounts?: BigNumber[]} = {}) { orders: Order[],
from: string,
opts: { fillTakerTokenAmounts?: BigNumber[] } = {},
) {
const params = formatters.createBatchFill(orders, undefined, opts.fillTakerTokenAmounts); const params = formatters.createBatchFill(orders, undefined, opts.fillTakerTokenAmounts);
const tx = await this._exchange.batchFillOrKillOrders( const tx = await this._exchange.batchFillOrKillOrders(
params.orderAddresses, params.orderAddresses,
@ -94,15 +104,20 @@ export class ExchangeWrapper {
_.each(tx.logs, log => wrapLogBigNumbers(log)); _.each(tx.logs, log => wrapLogBigNumbers(log));
return tx; return tx;
} }
public async fillOrdersUpToAsync(orders: Order[], from: string, public async fillOrdersUpToAsync(
orders: Order[],
from: string,
opts: { opts: {
fillTakerTokenAmount?: BigNumber; fillTakerTokenAmount?: BigNumber;
shouldThrowOnInsufficientBalanceOrAllowance?: boolean; shouldThrowOnInsufficientBalanceOrAllowance?: boolean;
} = {}) { } = {},
) {
const shouldThrowOnInsufficientBalanceOrAllowance = !!opts.shouldThrowOnInsufficientBalanceOrAllowance; const shouldThrowOnInsufficientBalanceOrAllowance = !!opts.shouldThrowOnInsufficientBalanceOrAllowance;
const params = formatters.createFillUpTo(orders, const params = formatters.createFillUpTo(
orders,
shouldThrowOnInsufficientBalanceOrAllowance, shouldThrowOnInsufficientBalanceOrAllowance,
opts.fillTakerTokenAmount); opts.fillTakerTokenAmount,
);
const tx = await this._exchange.fillOrdersUpTo( const tx = await this._exchange.fillOrdersUpTo(
params.orderAddresses, params.orderAddresses,
params.orderValues, params.orderValues,
@ -116,8 +131,11 @@ export class ExchangeWrapper {
_.each(tx.logs, log => wrapLogBigNumbers(log)); _.each(tx.logs, log => wrapLogBigNumbers(log));
return tx; return tx;
} }
public async batchCancelOrdersAsync(orders: Order[], from: string, public async batchCancelOrdersAsync(
opts: {cancelTakerTokenAmounts?: BigNumber[]} = {}) { orders: Order[],
from: string,
opts: { cancelTakerTokenAmounts?: BigNumber[] } = {},
) {
const params = formatters.createBatchCancel(orders, opts.cancelTakerTokenAmounts); const params = formatters.createBatchCancel(orders, opts.cancelTakerTokenAmounts);
const tx = await this._exchange.batchCancelOrders( const tx = await this._exchange.batchCancelOrders(
params.orderAddresses, params.orderAddresses,
@ -144,13 +162,19 @@ export class ExchangeWrapper {
); );
return isValidSignature; return isValidSignature;
} }
public async isRoundingErrorAsync(numerator: BigNumber, denominator: BigNumber, public async isRoundingErrorAsync(
target: BigNumber): Promise<boolean> { numerator: BigNumber,
denominator: BigNumber,
target: BigNumber,
): Promise<boolean> {
const isRoundingError = await this._exchange.isRoundingError(numerator, denominator, target); const isRoundingError = await this._exchange.isRoundingError(numerator, denominator, target);
return isRoundingError; return isRoundingError;
} }
public async getPartialAmountAsync(numerator: BigNumber, denominator: BigNumber, public async getPartialAmountAsync(
target: BigNumber): Promise<BigNumber> { numerator: BigNumber,
denominator: BigNumber,
target: BigNumber,
): Promise<BigNumber> {
const partialAmount = new BigNumber(await this._exchange.getPartialAmount(numerator, denominator, target)); const partialAmount = new BigNumber(await this._exchange.getPartialAmount(numerator, denominator, target));
return partialAmount; return partialAmount;
} }

View File

@ -5,9 +5,11 @@ import {Order} from './order';
import { BatchCancelOrders, BatchFillOrders, FillOrdersUpTo } from './types'; import { BatchCancelOrders, BatchFillOrders, FillOrdersUpTo } from './types';
export const formatters = { export const formatters = {
createBatchFill(orders: Order[], createBatchFill(
orders: Order[],
shouldThrowOnInsufficientBalanceOrAllowance: boolean, shouldThrowOnInsufficientBalanceOrAllowance: boolean,
fillTakerTokenAmounts: BigNumber[] = []) { fillTakerTokenAmounts: BigNumber[] = [],
) {
const batchFill: BatchFillOrders = { const batchFill: BatchFillOrders = {
orderAddresses: [], orderAddresses: [],
orderValues: [], orderValues: [],
@ -18,11 +20,21 @@ export const formatters = {
s: [], s: [],
}; };
_.forEach(orders, order => { _.forEach(orders, order => {
batchFill.orderAddresses.push([order.params.maker, order.params.taker, order.params.makerToken, batchFill.orderAddresses.push([
order.params.takerToken, order.params.feeRecipient]); order.params.maker,
batchFill.orderValues.push([order.params.makerTokenAmount, order.params.takerTokenAmount, order.params.taker,
order.params.makerFee, order.params.takerFee, order.params.makerToken,
order.params.expirationTimestampInSec, order.params.salt]); order.params.takerToken,
order.params.feeRecipient,
]);
batchFill.orderValues.push([
order.params.makerTokenAmount,
order.params.takerTokenAmount,
order.params.makerFee,
order.params.takerFee,
order.params.expirationTimestampInSec,
order.params.salt,
]);
batchFill.v.push(order.params.v); batchFill.v.push(order.params.v);
batchFill.r.push(order.params.r); batchFill.r.push(order.params.r);
batchFill.s.push(order.params.s); batchFill.s.push(order.params.s);
@ -32,9 +44,11 @@ export const formatters = {
}); });
return batchFill; return batchFill;
}, },
createFillUpTo(orders: Order[], createFillUpTo(
orders: Order[],
shouldThrowOnInsufficientBalanceOrAllowance: boolean, shouldThrowOnInsufficientBalanceOrAllowance: boolean,
fillTakerTokenAmount: BigNumber) { fillTakerTokenAmount: BigNumber,
) {
const fillUpTo: FillOrdersUpTo = { const fillUpTo: FillOrdersUpTo = {
orderAddresses: [], orderAddresses: [],
orderValues: [], orderValues: [],
@ -45,11 +59,21 @@ export const formatters = {
s: [], s: [],
}; };
orders.forEach(order => { orders.forEach(order => {
fillUpTo.orderAddresses.push([order.params.maker, order.params.taker, order.params.makerToken, fillUpTo.orderAddresses.push([
order.params.takerToken, order.params.feeRecipient]); order.params.maker,
fillUpTo.orderValues.push([order.params.makerTokenAmount, order.params.takerTokenAmount, order.params.taker,
order.params.makerFee, order.params.takerFee, order.params.makerToken,
order.params.expirationTimestampInSec, order.params.salt]); order.params.takerToken,
order.params.feeRecipient,
]);
fillUpTo.orderValues.push([
order.params.makerTokenAmount,
order.params.takerTokenAmount,
order.params.makerFee,
order.params.takerFee,
order.params.expirationTimestampInSec,
order.params.salt,
]);
fillUpTo.v.push(order.params.v); fillUpTo.v.push(order.params.v);
fillUpTo.r.push(order.params.r); fillUpTo.r.push(order.params.r);
fillUpTo.s.push(order.params.s); fillUpTo.s.push(order.params.s);
@ -63,11 +87,21 @@ export const formatters = {
cancelTakerTokenAmounts, cancelTakerTokenAmounts,
}; };
orders.forEach(order => { orders.forEach(order => {
batchCancel.orderAddresses.push([order.params.maker, order.params.taker, order.params.makerToken, batchCancel.orderAddresses.push([
order.params.takerToken, order.params.feeRecipient]); order.params.maker,
batchCancel.orderValues.push([order.params.makerTokenAmount, order.params.takerTokenAmount, order.params.taker,
order.params.makerFee, order.params.takerFee, order.params.makerToken,
order.params.expirationTimestampInSec, order.params.salt]); order.params.takerToken,
order.params.feeRecipient,
]);
batchCancel.orderValues.push([
order.params.makerTokenAmount,
order.params.takerTokenAmount,
order.params.makerFee,
order.params.takerFee,
order.params.expirationTimestampInSec,
order.params.salt,
]);
if (cancelTakerTokenAmounts.length < orders.length) { if (cancelTakerTokenAmounts.length < orders.length) {
batchCancel.cancelTakerTokenAmounts.push(order.params.takerTokenAmount); batchCancel.cancelTakerTokenAmounts.push(order.params.takerTokenAmount);
} }

View File

@ -24,11 +24,16 @@ export class MultiSigWrapper {
constructor(multiSigContractInstance: ContractInstance) { constructor(multiSigContractInstance: ContractInstance) {
this._multiSig = multiSigContractInstance; this._multiSig = multiSigContractInstance;
} }
public async submitTransactionAsync(destination: string, from: string, public async submitTransactionAsync(
destination: string,
from: string,
dataParams: TransactionDataParams, dataParams: TransactionDataParams,
value: number = 0) { value: number = 0,
) {
const { name, abi, args = [] } = dataParams; const { name, abi, args = [] } = dataParams;
const encoded = MultiSigWrapper.encodeFnArgs(name, abi, args); const encoded = MultiSigWrapper.encodeFnArgs(name, abi, args);
return this._multiSig.submitTransaction(destination, value, encoded, {from}); return this._multiSig.submitTransaction(destination, value, encoded, {
from,
});
} }
} }

View File

@ -11,12 +11,17 @@ export class OrderFactory {
this._defaultOrderParams = defaultOrderParams; this._defaultOrderParams = defaultOrderParams;
} }
public async newSignedOrderAsync(customOrderParams: OptionalOrderParams = {}) { public async newSignedOrderAsync(customOrderParams: OptionalOrderParams = {}) {
const randomExpiration = new BigNumber(Math.floor((Date.now() + (Math.random() * 100000000000)) / 1000)); const randomExpiration = new BigNumber(Math.floor((Date.now() + Math.random() * 100000000000) / 1000));
const orderParams: OrderParams = _.assign({}, { const orderParams: OrderParams = _.assign(
{},
{
expirationTimestampInSec: randomExpiration, expirationTimestampInSec: randomExpiration,
salt: ZeroEx.generatePseudoRandomSalt(), salt: ZeroEx.generatePseudoRandomSalt(),
taker: ZeroEx.NULL_ADDRESS, taker: ZeroEx.NULL_ADDRESS,
}, this._defaultOrderParams, customOrderParams); },
this._defaultOrderParams,
customOrderParams,
);
const order = new Order(orderParams); const order = new Order(orderParams);
await order.signAsync(); await order.signAsync();
return order; return order;

View File

@ -1,11 +1,7 @@
export const indexFilterValuesSchema = { export const indexFilterValuesSchema = {
id: '/IndexFilterValues', id: '/IndexFilterValues',
additionalProperties: { additionalProperties: {
oneOf: [ oneOf: [{ $ref: '/Number' }, { $ref: '/Address' }, { $ref: '/OrderHashSchema' }],
{$ref: '/Number'},
{$ref: '/Address'},
{$ref: '/OrderHashSchema'},
],
}, },
type: 'object', type: 'object',
}; };

View File

@ -15,8 +15,16 @@ export const orderSchema = {
exchangeContractAddress: { $ref: '/Address' }, exchangeContractAddress: { $ref: '/Address' },
}, },
required: [ required: [
'maker', 'taker', 'makerFee', 'takerFee', 'makerTokenAmount', 'takerTokenAmount', 'maker',
'salt', 'feeRecipient', 'expirationUnixTimestampSec', 'exchangeContractAddress', 'taker',
'makerFee',
'takerFee',
'makerTokenAmount',
'takerTokenAmount',
'salt',
'feeRecipient',
'expirationUnixTimestampSec',
'exchangeContractAddress',
], ],
type: 'object', type: 'object',
}; };

View File

@ -13,7 +13,12 @@ export const relayerApiFeesPayloadSchema = {
salt: { $ref: '/Number' }, salt: { $ref: '/Number' },
}, },
required: [ required: [
'exchangeContractAddress', 'maker', 'taker', 'makerTokenAddress', 'takerTokenAddress', 'exchangeContractAddress',
'expirationUnixTimestampSec', 'salt', 'maker',
'taker',
'makerTokenAddress',
'takerTokenAddress',
'expirationUnixTimestampSec',
'salt',
], ],
}; };

View File

@ -10,22 +10,13 @@ export const txDataSchema = {
from: { $ref: '/Address' }, from: { $ref: '/Address' },
to: { $ref: '/Address' }, to: { $ref: '/Address' },
value: { value: {
oneOf: [ oneOf: [{ $ref: '/Number' }, { $ref: '/JsNumber' }],
{$ref: '/Number'},
{$ref: '/JsNumber'},
],
}, },
gas: { gas: {
oneOf: [ oneOf: [{ $ref: '/Number' }, { $ref: '/JsNumber' }],
{$ref: '/Number'},
{$ref: '/JsNumber'},
],
}, },
gasPrice: { gasPrice: {
oneOf: [ oneOf: [{ $ref: '/Number' }, { $ref: '/JsNumber' }],
{$ref: '/Number'},
{$ref: '/JsNumber'},
],
}, },
data: { data: {
type: 'string', type: 'string',

View File

@ -1,43 +1,15 @@
import { import { addressSchema, numberSchema } from '../schemas/basic_type_schemas';
addressSchema, import { blockParamSchema, blockRangeSchema } from '../schemas/block_range_schema';
numberSchema, import { ecSignatureParameterSchema, ecSignatureSchema } from '../schemas/ec_signature_schema';
} from '../schemas/basic_type_schemas'; import { indexFilterValuesSchema } from '../schemas/index_filter_values_schema';
import { import { orderCancellationRequestsSchema } from '../schemas/order_cancel_schema';
blockParamSchema, import { orderFillOrKillRequestsSchema } from '../schemas/order_fill_or_kill_requests_schema';
blockRangeSchema, import { orderFillRequestsSchema } from '../schemas/order_fill_requests_schema';
} from '../schemas/block_range_schema'; import { orderHashSchema } from '../schemas/order_hash_schema';
import { import { orderSchema, signedOrderSchema } from '../schemas/order_schemas';
ecSignatureParameterSchema, import { relayerApiErrorResponseSchema } from '../schemas/relayer_api_error_response_schema';
ecSignatureSchema, import { relayerApiFeesPayloadSchema } from '../schemas/relayer_api_fees_payload_schema';
} from '../schemas/ec_signature_schema'; import { relayerApiFeesResponseSchema } from '../schemas/relayer_api_fees_response_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 {
relayerApiErrorResponseSchema,
} from '../schemas/relayer_api_error_response_schema';
import {
relayerApiFeesPayloadSchema,
} from '../schemas/relayer_api_fees_payload_schema';
import {
relayerApiFeesResponseSchema,
} from '../schemas/relayer_api_fees_response_schema';
import { import {
relayerApiOrderbookChannelSubscribePayload, relayerApiOrderbookChannelSubscribePayload,
relayerApiOrderbookChannelSubscribeSchema, relayerApiOrderbookChannelSubscribeSchema,
@ -46,26 +18,15 @@ import {
relayerApiOrderbookChannelSnapshotPayload, relayerApiOrderbookChannelSnapshotPayload,
relayerApiOrderbookChannelSnapshotSchema, relayerApiOrderbookChannelSnapshotSchema,
} from '../schemas/relayer_api_orderbook_channel_snapshot_schema'; } from '../schemas/relayer_api_orderbook_channel_snapshot_schema';
import { import { relayerApiOrderbookChannelUpdateSchema } from '../schemas/relayer_api_orderbook_channel_update_response_schema';
relayerApiOrderbookChannelUpdateSchema, import { relayerApiOrderBookResponseSchema } from '../schemas/relayer_api_orderbook_response_schema';
} from '../schemas/relayer_api_orderbook_channel_update_response_schema';
import {
relayerApiOrderBookResponseSchema,
} from '../schemas/relayer_api_orderbook_response_schema';
import { import {
relayerApiTokenPairsResponseSchema, relayerApiTokenPairsResponseSchema,
relayerApiTokenTradeInfoSchema, relayerApiTokenTradeInfoSchema,
} from '../schemas/relayer_api_token_pairs_response_schema'; } from '../schemas/relayer_api_token_pairs_response_schema';
import { import { signedOrdersSchema } from '../schemas/signed_orders_schema';
signedOrdersSchema, import { tokenSchema } from '../schemas/token_schema';
} from '../schemas/signed_orders_schema'; import { jsNumber, txDataSchema } from '../schemas/tx_data_schema';
import {
tokenSchema,
} from '../schemas/token_schema';
import {
jsNumber,
txDataSchema,
} from '../schemas/tx_data_schema';
export const schemas = { export const schemas = {
numberSchema, numberSchema,

View File

@ -122,11 +122,7 @@ describe('Schema', () => {
const v = 27; const v = 27;
const r = '0x61a3ed31b43c8780e905a260a35faefcc527be7516aa11c0256729b5b351bc33'; const r = '0x61a3ed31b43c8780e905a260a35faefcc527be7516aa11c0256729b5b351bc33';
const s = '0x40349190569279751135161d22529dc25add4f6069af05be04cacbda2ace2254'; const s = '0x40349190569279751135161d22529dc25add4f6069af05be04cacbda2ace2254';
const testCases = [ const testCases = [{}, { v }, { r, s, v: 31 }];
{},
{v},
{r, s, v: 31},
];
const shouldFail = true; const shouldFail = true;
validateAgainstSchema(testCases, ecSignatureSchema, shouldFail); validateAgainstSchema(testCases, ecSignatureSchema, shouldFail);
}); });
@ -152,37 +148,22 @@ describe('Schema', () => {
}); });
describe('#blockParamSchema', () => { describe('#blockParamSchema', () => {
it('should validate valid block param', () => { it('should validate valid block param', () => {
const testCases = [ const testCases = [42, 'latest', 'pending', 'earliest'];
42,
'latest',
'pending',
'earliest',
];
validateAgainstSchema(testCases, blockParamSchema); validateAgainstSchema(testCases, blockParamSchema);
}); });
it('should fail for invalid block param', () => { it('should fail for invalid block param', () => {
const testCases = [ const testCases = [{}, '42', 'pemding'];
{},
'42',
'pemding',
];
const shouldFail = true; const shouldFail = true;
validateAgainstSchema(testCases, blockParamSchema, shouldFail); validateAgainstSchema(testCases, blockParamSchema, shouldFail);
}); });
}); });
describe('#blockRangeSchema', () => { describe('#blockRangeSchema', () => {
it('should validate valid subscription opts', () => { it('should validate valid subscription opts', () => {
const testCases = [ const testCases = [{ fromBlock: 42, toBlock: 'latest' }, { fromBlock: 42 }, {}];
{fromBlock: 42, toBlock: 'latest'},
{fromBlock: 42},
{},
];
validateAgainstSchema(testCases, blockRangeSchema); validateAgainstSchema(testCases, blockRangeSchema);
}); });
it('should fail for invalid subscription opts', () => { it('should fail for invalid subscription opts', () => {
const testCases = [ const testCases = [{ fromBlock: '42' }];
{fromBlock: '42'},
];
const shouldFail = true; const shouldFail = true;
validateAgainstSchema(testCases, blockRangeSchema, shouldFail); validateAgainstSchema(testCases, blockRangeSchema, shouldFail);
}); });
@ -196,9 +177,7 @@ describe('Schema', () => {
url: 'https://0xproject.com', url: 'https://0xproject.com',
}; };
it('should validate valid token', () => { it('should validate valid token', () => {
const testCases = [ const testCases = [token];
token,
];
validateAgainstSchema(testCases, tokenSchema); validateAgainstSchema(testCases, tokenSchema);
}); });
it('should fail for invalid token', () => { it('should fail for invalid token', () => {
@ -235,9 +214,7 @@ describe('Schema', () => {
}; };
describe('#orderSchema', () => { describe('#orderSchema', () => {
it('should validate valid order', () => { it('should validate valid order', () => {
const testCases = [ const testCases = [order];
order,
];
validateAgainstSchema(testCases, orderSchema); validateAgainstSchema(testCases, orderSchema);
}); });
it('should fail for invalid order', () => { it('should fail for invalid order', () => {
@ -267,28 +244,18 @@ describe('Schema', () => {
}; };
describe('#signedOrdersSchema', () => { describe('#signedOrdersSchema', () => {
it('should validate valid signed orders', () => { it('should validate valid signed orders', () => {
const testCases = [ const testCases = [[signedOrder], []];
[signedOrder],
[],
];
validateAgainstSchema(testCases, signedOrdersSchema); validateAgainstSchema(testCases, signedOrdersSchema);
}); });
it('should fail for invalid signed orders', () => { it('should fail for invalid signed orders', () => {
const testCases = [ const testCases = [[signedOrder, 1]];
[
signedOrder,
1,
],
];
const shouldFail = true; const shouldFail = true;
validateAgainstSchema(testCases, signedOrdersSchema, shouldFail); validateAgainstSchema(testCases, signedOrdersSchema, shouldFail);
}); });
}); });
describe('#signedOrderSchema', () => { describe('#signedOrderSchema', () => {
it('should validate valid signed order', () => { it('should validate valid signed order', () => {
const testCases = [ const testCases = [signedOrder];
signedOrder,
];
validateAgainstSchema(testCases, signedOrderSchema); validateAgainstSchema(testCases, signedOrderSchema);
}); });
it('should fail for invalid signed order', () => { it('should fail for invalid signed order', () => {
@ -310,9 +277,7 @@ describe('Schema', () => {
}, },
]; ];
it('should validate valid order fill or kill requests', () => { it('should validate valid order fill or kill requests', () => {
const testCases = [ const testCases = [orderFillOrKillRequests];
orderFillOrKillRequests,
];
validateAgainstSchema(testCases, orderFillOrKillRequestsSchema); validateAgainstSchema(testCases, orderFillOrKillRequestsSchema);
}); });
it('should fail for invalid order fill or kill requests', () => { it('should fail for invalid order fill or kill requests', () => {
@ -336,9 +301,7 @@ describe('Schema', () => {
}, },
]; ];
it('should validate valid order cancellation requests', () => { it('should validate valid order cancellation requests', () => {
const testCases = [ const testCases = [orderCancellationRequests];
orderCancellationRequests,
];
validateAgainstSchema(testCases, orderCancellationRequestsSchema); validateAgainstSchema(testCases, orderCancellationRequestsSchema);
}); });
it('should fail for invalid order cancellation requests', () => { it('should fail for invalid order cancellation requests', () => {
@ -362,9 +325,7 @@ describe('Schema', () => {
}, },
]; ];
it('should validate valid order fill requests', () => { it('should validate valid order fill requests', () => {
const testCases = [ const testCases = [orderFillRequests];
orderFillRequests,
];
validateAgainstSchema(testCases, orderFillRequestsSchema); validateAgainstSchema(testCases, orderFillRequestsSchema);
}); });
it('should fail for invalid order fill requests', () => { it('should fail for invalid order fill requests', () => {
@ -559,12 +520,8 @@ describe('Schema', () => {
channel: 'orderbook', channel: 'orderbook',
requestId: 2, requestId: 2,
payload: { payload: {
bids: [ bids: [signedOrder],
signedOrder, asks: [signedOrder],
],
asks: [
signedOrder,
],
}, },
}, },
]; ];
@ -577,12 +534,8 @@ describe('Schema', () => {
channel: 'orderbook', channel: 'orderbook',
requestId: 2, requestId: 2,
payload: { payload: {
bids: [ bids: [signedOrder],
signedOrder, asks: [signedOrder],
],
asks: [
signedOrder,
],
}, },
}, },
{ {
@ -590,24 +543,16 @@ describe('Schema', () => {
channel: 'bar', channel: 'bar',
requestId: 2, requestId: 2,
payload: { payload: {
bids: [ bids: [signedOrder],
signedOrder, asks: [signedOrder],
],
asks: [
signedOrder,
],
}, },
}, },
{ {
type: 'snapshot', type: 'snapshot',
channel: 'orderbook', channel: 'orderbook',
payload: { payload: {
bids: [ bids: [signedOrder],
signedOrder, asks: [signedOrder],
],
asks: [
signedOrder,
],
}, },
}, },
{ {
@ -615,12 +560,8 @@ describe('Schema', () => {
channel: 'orderbook', channel: 'orderbook',
requestId: '2', requestId: '2',
payload: { payload: {
bids: [ bids: [signedOrder],
signedOrder, asks: [signedOrder],
],
asks: [
signedOrder,
],
}, },
}, },
{ {
@ -628,9 +569,7 @@ describe('Schema', () => {
channel: 'orderbook', channel: 'orderbook',
requestId: 2, requestId: 2,
payload: { payload: {
bids: [ bids: [signedOrder],
signedOrder,
],
}, },
}, },
{ {
@ -638,9 +577,7 @@ describe('Schema', () => {
channel: 'orderbook', channel: 'orderbook',
requestId: 2, requestId: 2,
payload: { payload: {
asks: [ asks: [signedOrder],
signedOrder,
],
}, },
}, },
{ {
@ -648,12 +585,8 @@ describe('Schema', () => {
channel: 'orderbook', channel: 'orderbook',
requestId: 2, requestId: 2,
payload: { payload: {
bids: [ bids: [signedOrder],
signedOrder, asks: [{}],
],
asks: [
{},
],
}, },
}, },
{ {
@ -661,12 +594,8 @@ describe('Schema', () => {
channel: 'orderbook', channel: 'orderbook',
requestId: 2, requestId: 2,
payload: { payload: {
bids: [ bids: [{}],
{}, asks: [signedOrder],
],
asks: [
signedOrder,
],
}, },
}, },
]; ];
@ -941,18 +870,11 @@ describe('Schema', () => {
}); });
describe('#jsNumberSchema', () => { describe('#jsNumberSchema', () => {
it('should validate valid js number', () => { it('should validate valid js number', () => {
const testCases = [ const testCases = [1, 42];
1,
42,
];
validateAgainstSchema(testCases, jsNumber); validateAgainstSchema(testCases, jsNumber);
}); });
it('should fail for invalid js number', () => { it('should fail for invalid js number', () => {
const testCases = [ const testCases = [NaN, -1, new BigNumber(1)];
NaN,
-1,
new BigNumber(1),
];
const shouldFail = true; const shouldFail = true;
validateAgainstSchema(testCases, jsNumber, shouldFail); validateAgainstSchema(testCases, jsNumber, shouldFail);
}); });

View File

@ -3,9 +3,10 @@ export const configs = {
DISPENSER_PRIVATE_KEY: process.env.DISPENSER_PRIVATE_KEY, DISPENSER_PRIVATE_KEY: process.env.DISPENSER_PRIVATE_KEY,
ENVIRONMENT: process.env.FAUCET_ENVIRONMENT, ENVIRONMENT: process.env.FAUCET_ENVIRONMENT,
ROLLBAR_ACCESS_KEY: process.env.FAUCET_ROLLBAR_ACCESS_KEY, ROLLBAR_ACCESS_KEY: process.env.FAUCET_ROLLBAR_ACCESS_KEY,
RPC_URL: process.env.FAUCET_ENVIRONMENT === 'development' ? RPC_URL:
'http://127.0.0.1:8545' : process.env.FAUCET_ENVIRONMENT === 'development'
`https://kovan.infura.io/${process.env.INFURA_API_KEY}`, ? 'http://127.0.0.1:8545'
: `https://kovan.infura.io/${process.env.INFURA_API_KEY}`,
ZRX_TOKEN_ADDRESS: '0x6ff6c0ff1d68b964901f986d4c9fa3ac68346570', ZRX_TOKEN_ADDRESS: '0x6ff6c0ff1d68b964901f986d4c9fa3ac68346570',
KOVAN_NETWORK_ID: 42, KOVAN_NETWORK_ID: 42,
}; };

View File

@ -78,9 +78,11 @@ export class Handler {
const engine = new ProviderEngine(); const engine = new ProviderEngine();
engine.addProvider(new NonceSubprovider()); engine.addProvider(new NonceSubprovider());
engine.addProvider(new HookedWalletSubprovider(idManagement)); engine.addProvider(new HookedWalletSubprovider(idManagement));
engine.addProvider(new RpcSubprovider({ engine.addProvider(
new RpcSubprovider({
rpcUrl, rpcUrl,
})); }),
);
engine.start(); engine.start();
return engine; return engine;
} }

View File

@ -8,9 +8,7 @@ type Callback = (err: Error, accounts: any) => void;
export const idManagement = { export const idManagement = {
getAccounts(callback: Callback) { getAccounts(callback: Callback) {
utils.consoleLog(`configs.DISPENSER_ADDRESS: ${configs.DISPENSER_ADDRESS}`); utils.consoleLog(`configs.DISPENSER_ADDRESS: ${configs.DISPENSER_ADDRESS}`);
callback(null, [ callback(null, [configs.DISPENSER_ADDRESS]);
configs.DISPENSER_ADDRESS,
]);
}, },
approveTransaction(txData: object, callback: Callback) { approveTransaction(txData: object, callback: Callback) {
callback(null, true); callback(null, true);

View File

@ -44,7 +44,6 @@ export class RequestQueue {
const recipientAddress = this.queue.shift(); const recipientAddress = this.queue.shift();
// tslint:disable-next-line:no-floating-promises // tslint:disable-next-line:no-floating-promises
this.processNextRequestFireAndForgetAsync(recipientAddress); this.processNextRequestFireAndForgetAsync(recipientAddress);
}, this.queueIntervalMs); }, this.queueIntervalMs);
} }
protected stop() { protected stop() {

View File

@ -16,7 +16,9 @@ app.use((req, res, next) => {
}); });
const handler = new Handler(); const handler = new Handler();
app.get('/ping', (req: express.Request, res: express.Response) => { res.status(200).send('pong'); }); app.get('/ping', (req: express.Request, res: express.Response) => {
res.status(200).send('pong');
});
app.get('/ether/:recipient', handler.dispenseEther.bind(handler)); app.get('/ether/:recipient', handler.dispenseEther.bind(handler));
app.get('/zrx/:recipient', handler.dispenseZRX.bind(handler)); app.get('/zrx/:recipient', handler.dispenseZRX.bind(handler));

View File

@ -31,7 +31,10 @@ export class ZRXRequestQueue extends RequestQueue {
const baseUnitAmount = ZeroEx.toBaseUnitAmount(DISPENSE_AMOUNT_ZRX, 18); const baseUnitAmount = ZeroEx.toBaseUnitAmount(DISPENSE_AMOUNT_ZRX, 18);
try { try {
await this._zeroEx.token.transferAsync( await this._zeroEx.token.transferAsync(
configs.ZRX_TOKEN_ADDRESS, configs.DISPENSER_ADDRESS, recipientAddress, baseUnitAmount, configs.ZRX_TOKEN_ADDRESS,
configs.DISPENSER_ADDRESS,
recipientAddress,
baseUnitAmount,
); );
utils.consoleLog(`Sent ${DISPENSE_AMOUNT_ZRX} ZRX to ${recipientAddress}`); utils.consoleLog(`Sent ${DISPENSE_AMOUNT_ZRX} ZRX to ${recipientAddress}`);
} catch (err) { } catch (err) {

View File

@ -47,10 +47,16 @@ declare module 'ledgerco' {
export class eth { export class eth {
public comm: comm; public comm: comm;
constructor(comm: comm); constructor(comm: comm);
public getAddress_async(path: string, display?: boolean, chaincode?: boolean): public getAddress_async(
Promise<{publicKey: string; address: string; chainCode: string}>; path: string,
display?: boolean,
chaincode?: boolean,
): Promise<{ publicKey: string; address: string; chainCode: string }>;
public signTransaction_async(path: string, rawTxHex: string): Promise<ECSignatureString>; public signTransaction_async(path: string, rawTxHex: string): Promise<ECSignatureString>;
public getAppConfiguration_async(): Promise<{ arbitraryDataEnabled: number; version: string }>; public getAppConfiguration_async(): Promise<{
arbitraryDataEnabled: number;
version: string;
}>;
public signPersonalMessage_async(path: string, messageHex: string): Promise<ECSignature>; public signPersonalMessage_async(path: string, messageHex: string): Promise<ECSignature>;
} }
} }
@ -75,7 +81,9 @@ declare module 'web3-provider-engine/subproviders/rpc' {
class RpcSubprovider { class RpcSubprovider {
constructor(options: { rpcUrl: string }); constructor(options: { rpcUrl: string });
public handleRequest( public handleRequest(
payload: Web3.JSONRPCRequestPayload, next: () => void, end: (err: Error|null, data?: any) => void, payload: Web3.JSONRPCRequestPayload,
next: () => void,
end: (err: Error | null, data?: any) => void,
): void; ): void;
} }
export = RpcSubprovider; export = RpcSubprovider;

View File

@ -8,14 +8,8 @@ import {LedgerEthereumClient} from './types';
export { InjectedWeb3Subprovider } from './subproviders/injected_web3'; export { InjectedWeb3Subprovider } from './subproviders/injected_web3';
export { RedundantRPCSubprovider } from './subproviders/redundant_rpc'; export { RedundantRPCSubprovider } from './subproviders/redundant_rpc';
export { export { LedgerSubprovider } from './subproviders/ledger';
LedgerSubprovider, export { ECSignature, LedgerWalletSubprovider, LedgerCommunicationClient } from './types';
} from './subproviders/ledger';
export {
ECSignature,
LedgerWalletSubprovider,
LedgerCommunicationClient,
} from './types';
/** /**
* A factory method for creating a LedgerEthereumClient usable in a browser context. * A factory method for creating a LedgerEthereumClient usable in a browser context.

View File

@ -14,7 +14,9 @@ export class InjectedWeb3Subprovider {
this._injectedWeb3 = injectedWeb3; this._injectedWeb3 = injectedWeb3;
} }
public handleRequest( public handleRequest(
payload: Web3.JSONRPCRequestPayload, next: () => void, end: (err: Error|null, result: any) => void, payload: Web3.JSONRPCRequestPayload,
next: () => void,
end: (err: Error | null, result: any) => void,
) { ) {
switch (payload.method) { switch (payload.method) {
case 'web3_clientVersion': case 'web3_clientVersion':

View File

@ -44,12 +44,11 @@ export class LedgerSubprovider extends Subprovider {
this._networkId = config.networkId; this._networkId = config.networkId;
this._ledgerEthereumClientFactoryAsync = config.ledgerEthereumClientFactoryAsync; this._ledgerEthereumClientFactoryAsync = config.ledgerEthereumClientFactoryAsync;
this._derivationPath = config.derivationPath || DEFAULT_DERIVATION_PATH; this._derivationPath = config.derivationPath || DEFAULT_DERIVATION_PATH;
this._shouldAlwaysAskForConfirmation = !_.isUndefined(config.accountFetchingConfigs) && this._shouldAlwaysAskForConfirmation =
!_.isUndefined( !_.isUndefined(config.accountFetchingConfigs) &&
config.accountFetchingConfigs.shouldAskForOnDeviceConfirmation, !_.isUndefined(config.accountFetchingConfigs.shouldAskForOnDeviceConfirmation)
) ? ? config.accountFetchingConfigs.shouldAskForOnDeviceConfirmation
config.accountFetchingConfigs.shouldAskForOnDeviceConfirmation : : ASK_FOR_ON_DEVICE_CONFIRMATION;
ASK_FOR_ON_DEVICE_CONFIRMATION;
this._derivationPathIndex = 0; this._derivationPathIndex = 0;
} }
public getPath(): string { public getPath(): string {
@ -62,7 +61,9 @@ export class LedgerSubprovider extends Subprovider {
this._derivationPathIndex = pathIndex; this._derivationPathIndex = pathIndex;
} }
public async handleRequest( public async handleRequest(
payload: Web3.JSONRPCRequestPayload, next: () => void, end: (err: Error|null, result?: any) => void, payload: Web3.JSONRPCRequestPayload,
next: () => void,
end: (err: Error | null, result?: any) => void,
) { ) {
let accounts; let accounts;
let txParams; let txParams;
@ -132,7 +133,9 @@ export class LedgerSubprovider extends Subprovider {
let ledgerResponse; let ledgerResponse;
try { try {
ledgerResponse = await this._ledgerClientIfExists.getAddress_async( ledgerResponse = await this._ledgerClientIfExists.getAddress_async(
this._derivationPath, this._shouldAlwaysAskForConfirmation, SHOULD_GET_CHAIN_CODE, this._derivationPath,
this._shouldAlwaysAskForConfirmation,
SHOULD_GET_CHAIN_CODE,
); );
} finally { } finally {
await this._destroyLedgerClientAsync(); await this._destroyLedgerClientAsync();
@ -147,9 +150,9 @@ export class LedgerSubprovider extends Subprovider {
const derivedHDNode = hdKey.derive(`m/${i + this._derivationPathIndex}`); const derivedHDNode = hdKey.derive(`m/${i + this._derivationPathIndex}`);
const derivedPublicKey = derivedHDNode.publicKey; const derivedPublicKey = derivedHDNode.publicKey;
const shouldSanitizePublicKey = true; const shouldSanitizePublicKey = true;
const ethereumAddressUnprefixed = ethUtil.publicToAddress( const ethereumAddressUnprefixed = ethUtil
derivedPublicKey, shouldSanitizePublicKey, .publicToAddress(derivedPublicKey, shouldSanitizePublicKey)
).toString('hex'); .toString('hex');
const ethereumAddressPrefixed = ethUtil.addHexPrefix(ethereumAddressUnprefixed); const ethereumAddressPrefixed = ethUtil.addHexPrefix(ethereumAddressUnprefixed);
accounts.push(ethereumAddressPrefixed.toLowerCase()); accounts.push(ethereumAddressPrefixed.toLowerCase());
} }
@ -195,7 +198,9 @@ export class LedgerSubprovider extends Subprovider {
try { try {
const derivationPath = this._getDerivationPath(); const derivationPath = this._getDerivationPath();
const result = await this._ledgerClientIfExists.signPersonalMessage_async( const result = await this._ledgerClientIfExists.signPersonalMessage_async(
derivationPath, ethUtil.stripHexPrefix(data)); derivationPath,
ethUtil.stripHexPrefix(data),
);
const v = result.v - 27; const v = result.v - 27;
let vHex = v.toString(16); let vHex = v.toString(16);
if (vHex.length < 2) { if (vHex.length < 2) {

View File

@ -9,7 +9,9 @@ import {Subprovider} from './subprovider';
export class RedundantRPCSubprovider extends Subprovider { export class RedundantRPCSubprovider extends Subprovider {
private _rpcs: RpcSubprovider[]; private _rpcs: RpcSubprovider[];
private static async _firstSuccessAsync( private static async _firstSuccessAsync(
rpcs: RpcSubprovider[], payload: JSONRPCPayload, next: () => void, rpcs: RpcSubprovider[],
payload: JSONRPCPayload,
next: () => void,
): Promise<any> { ): Promise<any> {
let lastErr: Error | undefined; let lastErr: Error | undefined;
for (const rpc of rpcs) { for (const rpc of rpcs) {
@ -34,8 +36,11 @@ export class RedundantRPCSubprovider extends Subprovider {
}); });
} }
// tslint:disable-next-line:async-suffix // tslint:disable-next-line:async-suffix
public async handleRequest(payload: JSONRPCPayload, next: () => void, public async handleRequest(
end: (err: Error|null, data?: any) => void): Promise<void> { payload: JSONRPCPayload,
next: () => void,
end: (err: Error | null, data?: any) => void,
): Promise<void> {
const rpcsCopy = this._rpcs.slice(); const rpcsCopy = this._rpcs.slice();
try { try {
const data = await RedundantRPCSubprovider._firstSuccessAsync(rpcsCopy, payload, next); const data = await RedundantRPCSubprovider._firstSuccessAsync(rpcsCopy, payload, next);
@ -43,6 +48,5 @@ export class RedundantRPCSubprovider extends Subprovider {
} catch (err) { } catch (err) {
end(err); end(err);
} }
} }
} }

Some files were not shown because too many files have changed in this diff Show More