aboutsummaryrefslogtreecommitdiffstats
path: root/packages/0x.js
diff options
context:
space:
mode:
Diffstat (limited to 'packages/0x.js')
-rw-r--r--packages/0x.js/CHANGELOG.json14
-rw-r--r--packages/0x.js/package.json28
-rw-r--r--packages/0x.js/src/0x.ts121
-rw-r--r--packages/0x.js/src/abstract/balance_and_proxy_allowance_fetcher.ts6
-rw-r--r--packages/0x.js/src/abstract/order_filled_cancelled_fetcher.ts6
-rw-r--r--packages/0x.js/src/artifacts.ts18
-rw-r--r--packages/0x.js/src/contract_wrappers/contract_wrapper.ts202
-rw-r--r--packages/0x.js/src/contract_wrappers/ether_token_wrapper.ts204
-rw-r--r--packages/0x.js/src/contract_wrappers/exchange_wrapper.ts964
-rw-r--r--packages/0x.js/src/contract_wrappers/token_registry_wrapper.ts133
-rw-r--r--packages/0x.js/src/contract_wrappers/token_transfer_proxy_wrapper.ts75
-rw-r--r--packages/0x.js/src/contract_wrappers/token_wrapper.ts434
-rw-r--r--packages/0x.js/src/fetchers/simple_balance_and_proxy_allowance_fetcher.ts28
-rw-r--r--packages/0x.js/src/fetchers/simple_order_filled_cancelled_fetcher.ts28
-rw-r--r--packages/0x.js/src/index.ts52
-rw-r--r--packages/0x.js/src/order_watcher/event_watcher.ts99
-rw-r--r--packages/0x.js/src/order_watcher/expiration_watcher.ts87
-rw-r--r--packages/0x.js/src/order_watcher/order_state_watcher.ts381
-rw-r--r--packages/0x.js/src/order_watcher/remaining_fillable_calculator.ts95
-rw-r--r--packages/0x.js/src/stores/balance_proxy_allowance_lazy_store.ts91
-rw-r--r--packages/0x.js/src/stores/order_filled_cancelled_lazy_store.ts67
-rw-r--r--packages/0x.js/src/types.ts260
-rw-r--r--packages/0x.js/src/utils/assert.ts31
-rw-r--r--packages/0x.js/src/utils/constants.ts5
-rw-r--r--packages/0x.js/src/utils/decorators.ts91
-rw-r--r--packages/0x.js/src/utils/exchange_transfer_simulator.ts115
-rw-r--r--packages/0x.js/src/utils/filter_utils.ts95
-rw-r--r--packages/0x.js/src/utils/order_state_utils.ts138
-rw-r--r--packages/0x.js/src/utils/order_validation_utils.ts199
-rw-r--r--packages/0x.js/src/utils/utils.ts13
-rw-r--r--packages/0x.js/test/0x.js_test.ts7
-rw-r--r--packages/0x.js/test/assert_test.ts0
-rw-r--r--packages/0x.js/test/ether_token_wrapper_test.ts386
-rw-r--r--packages/0x.js/test/event_watcher_test.ts125
-rw-r--r--packages/0x.js/test/exchange_transfer_simulator_test.ts117
-rw-r--r--packages/0x.js/test/exchange_wrapper_test.ts1195
-rw-r--r--packages/0x.js/test/expiration_watcher_test.ts195
-rw-r--r--packages/0x.js/test/order_state_watcher_test.ts558
-rw-r--r--packages/0x.js/test/order_validation_test.ts507
-rw-r--r--packages/0x.js/test/remaining_fillable_calculator_test.ts234
-rw-r--r--packages/0x.js/test/subscription_test.ts82
-rw-r--r--packages/0x.js/test/token_registry_wrapper_test.ts128
-rw-r--r--packages/0x.js/test/token_transfer_proxy_wrapper_test.ts35
-rw-r--r--packages/0x.js/test/token_wrapper_test.ts528
-rw-r--r--packages/0x.js/test/utils/fill_scenarios.ts202
-rw-r--r--packages/0x.js/test/utils/report_callback_errors.ts66
-rw-r--r--packages/0x.js/test/utils/token_utils.ts3
47 files changed, 94 insertions, 8354 deletions
diff --git a/packages/0x.js/CHANGELOG.json b/packages/0x.js/CHANGELOG.json
index bdc575903..5e4a726b1 100644
--- a/packages/0x.js/CHANGELOG.json
+++ b/packages/0x.js/CHANGELOG.json
@@ -1,5 +1,19 @@
[
{
+ "version": "0.38.0",
+ "changes": [
+ {
+ "note": "Renamed createOrderStateWatcher to createOrderWatcherAsync since it is now async",
+ "pr": 579
+ },
+ {
+ "note":
+ "Renamed ZeroExError to ContractWrappersErrors since they now lives in the @0xproject/contract-wrappers subpackage",
+ "pr": 579
+ }
+ ]
+ },
+ {
"timestamp": 1525477860,
"version": "0.37.2",
"changes": [
diff --git a/packages/0x.js/package.json b/packages/0x.js/package.json
index dafd8af88..d048c8be6 100644
--- a/packages/0x.js/package.json
+++ b/packages/0x.js/package.json
@@ -21,7 +21,7 @@
"test": "run-s clean test:commonjs",
"test:coverage": "nyc npm run test --all && yarn coverage:report:lcov",
"coverage:report:lcov": "nyc report --reporter=text-lcov > coverage/lcov.info",
- "clean": "shx rm -rf _bundles lib test_temp scripts",
+ "clean": "shx rm -rf _bundles lib test_temp scripts src/contract_wrappers/generated",
"build:umd:prod": "NODE_ENV=production webpack",
"build:commonjs": "tsc && copyfiles -u 2 './src/compact_artifacts/**/*.json' ./lib/src/compact_artifacts && copyfiles -u 3 './lib/src/monorepo_scripts/**/*' ./scripts",
"test:commonjs": "run-s build:commonjs run_mocha",
@@ -41,6 +41,13 @@
"docPublishConfigs": {
"extraFileIncludes": [
"../types/src/index.ts",
+ "../contract-wrappers/src/types.ts",
+ "../contract-wrappers/src/contract_wrappers/ether_token_wrapper.ts",
+ "../contract-wrappers/src/contract_wrappers/exchange_wrapper.ts",
+ "../contract-wrappers/src/contract_wrappers/token_registry_wrapper.ts",
+ "../contract-wrappers/src/contract_wrappers/token_transfer_proxy_wrapper.ts",
+ "../contract-wrappers/src/contract_wrappers/token_wrapper.ts",
+ "../order-watcher/src/order_watcher/order_watcher.ts",
"./src/contract_wrappers/generated/ether_token.ts",
"./src/contract_wrappers/generated/token.ts",
"./src/contract_wrappers/generated/exchange.ts"
@@ -63,15 +70,11 @@
"@0xproject/dev-utils": "^0.4.1",
"@0xproject/migrations": "^0.0.5",
"@0xproject/monorepo-scripts": "^0.1.19",
- "@0xproject/subproviders": "^0.10.1",
"@0xproject/tslint-config": "^0.4.17",
- "@types/bintrees": "^1.0.2",
"@types/lodash": "4.14.104",
"@types/mocha": "^2.2.42",
"@types/node": "^8.0.53",
- "@types/request": "2.47.0",
"@types/sinon": "^2.2.2",
- "@types/uuid": "^3.4.2",
"awesome-typescript-loader": "^3.1.3",
"chai": "^4.0.1",
"chai-as-promised": "^7.1.0",
@@ -84,35 +87,26 @@
"nyc": "^11.0.1",
"opn-cli": "^3.1.0",
"prettier": "^1.11.1",
- "request": "^2.81.0",
"shx": "^0.2.2",
"sinon": "^4.0.0",
"source-map-support": "^0.5.0",
"tslint": "5.8.0",
"typedoc": "0xProject/typedoc",
"typescript": "2.7.1",
- "web3-provider-engine": "^14.0.4",
"webpack": "^3.1.0"
},
"dependencies": {
"@0xproject/assert": "^0.2.9",
"@0xproject/base-contract": "^0.3.1",
- "@0xproject/json-schemas": "^0.7.23",
+ "@0xproject/contract-wrappers": "^0.0.1",
+ "@0xproject/order-watcher": "^0.0.1",
"@0xproject/order-utils": "^0.0.4",
"@0xproject/types": "^0.6.3",
"@0xproject/typescript-typings": "^0.3.1",
"@0xproject/utils": "^0.6.1",
"@0xproject/web3-wrapper": "^0.6.3",
- "bintrees": "^1.0.2",
- "bn.js": "^4.11.8",
- "ethereumjs-abi": "^0.6.4",
- "ethereumjs-blockstream": "^2.0.6",
- "ethereumjs-util": "^5.1.1",
"ethers": "^3.0.15",
- "js-sha3": "^0.7.0",
- "lodash": "^4.17.4",
- "uuid": "^3.1.0",
- "web3": "^0.20.0"
+ "lodash": "^4.17.4"
},
"publishConfig": {
"access": "public"
diff --git a/packages/0x.js/src/0x.ts b/packages/0x.js/src/0x.ts
index f603ad644..a4ca3efc2 100644
--- a/packages/0x.js/src/0x.ts
+++ b/packages/0x.js/src/0x.ts
@@ -1,4 +1,13 @@
-import { schemas, SchemaValidator } from '@0xproject/json-schemas';
+import { assert } from '@0xproject/assert';
+import {
+ ContractWrappers,
+ ContractWrappersConfig,
+ EtherTokenWrapper,
+ ExchangeWrapper,
+ TokenRegistryWrapper,
+ TokenTransferProxyWrapper,
+ TokenWrapper,
+} from '@0xproject/contract-wrappers';
import {
generatePseudoRandomSalt,
getOrderHashHex,
@@ -6,27 +15,13 @@ import {
isValidSignature,
signOrderHashAsync,
} from '@0xproject/order-utils';
+import { OrderWatcher, OrderWatcherConfig } from '@0xproject/order-watcher';
import { ECSignature, Order, Provider, SignedOrder, TransactionReceiptWithDecodedLogs } from '@0xproject/types';
-import { AbiDecoder, BigNumber, intervalUtils } from '@0xproject/utils';
+import { BigNumber } from '@0xproject/utils';
import { Web3Wrapper } from '@0xproject/web3-wrapper';
-import * as ethUtil from 'ethereumjs-util';
import * as _ from 'lodash';
-import { artifacts } from './artifacts';
-import { EtherTokenWrapper } from './contract_wrappers/ether_token_wrapper';
-import { ExchangeWrapper } from './contract_wrappers/exchange_wrapper';
-import { TokenRegistryWrapper } from './contract_wrappers/token_registry_wrapper';
-import { TokenTransferProxyWrapper } from './contract_wrappers/token_transfer_proxy_wrapper';
-import { TokenWrapper } from './contract_wrappers/token_wrapper';
-import { OrderStateWatcher } from './order_watcher/order_state_watcher';
-import { zeroExConfigSchema } from './schemas/zero_ex_config_schema';
-import { zeroExPrivateNetworkConfigSchema } from './schemas/zero_ex_private_network_config_schema';
-import { zeroExPublicNetworkConfigSchema } from './schemas/zero_ex_public_network_config_schema';
-import { OrderStateWatcherConfig, ZeroExConfig, ZeroExError } from './types';
-import { assert } from './utils/assert';
import { constants } from './utils/constants';
-import { decorators } from './utils/decorators';
-import { utils } from './utils/utils';
/**
* The ZeroEx class is the single entry-point into the 0x.js library. It contains all of the library's functionality
@@ -62,7 +57,7 @@ export class ZeroEx {
* tokenTransferProxy smart contract.
*/
public proxy: TokenTransferProxyWrapper;
- private _web3Wrapper: Web3Wrapper;
+ private _contractWrappers: ContractWrappers;
/**
* Generates a pseudo-random 256-bit salt.
* The salt can be included in a 0x order, ensuring that the order generates a unique orderHash
@@ -136,40 +131,15 @@ export class ZeroEx {
* @param config The configuration object. Look up the type for the description.
* @return An instance of the 0x.js ZeroEx class.
*/
- constructor(provider: Provider, config: ZeroExConfig) {
+ constructor(provider: Provider, config: ContractWrappersConfig) {
assert.isWeb3Provider('provider', provider);
- assert.doesConformToSchema('config', config, zeroExConfigSchema, [
- zeroExPrivateNetworkConfigSchema,
- zeroExPublicNetworkConfigSchema,
- ]);
- const artifactJSONs = _.values(artifacts);
- const abiArrays = _.map(artifactJSONs, artifact => artifact.abi);
- const txDefaults = {
- gasPrice: config.gasPrice,
- };
- this._web3Wrapper = new Web3Wrapper(provider, txDefaults);
- _.forEach(abiArrays, abi => {
- this._web3Wrapper.abiDecoder.addABI(abi);
- });
- this.proxy = new TokenTransferProxyWrapper(
- this._web3Wrapper,
- config.networkId,
- config.tokenTransferProxyContractAddress,
- );
- this.token = new TokenWrapper(this._web3Wrapper, config.networkId, this.proxy);
- this.exchange = new ExchangeWrapper(
- this._web3Wrapper,
- config.networkId,
- this.token,
- config.exchangeContractAddress,
- config.zrxContractAddress,
- );
- this.tokenRegistry = new TokenRegistryWrapper(
- this._web3Wrapper,
- config.networkId,
- config.tokenRegistryContractAddress,
- );
- this.etherToken = new EtherTokenWrapper(this._web3Wrapper, config.networkId, this.token);
+ this._contractWrappers = new ContractWrappers(provider, config);
+
+ this.proxy = this._contractWrappers.proxy;
+ this.token = this._contractWrappers.token;
+ this.exchange = this._contractWrappers.exchange;
+ this.tokenRegistry = this._contractWrappers.tokenRegistry;
+ this.etherToken = this._contractWrappers.etherToken;
}
/**
* Sets a new web3 provider for 0x.js. Updating the provider will stop all
@@ -178,31 +148,23 @@ export class ZeroEx {
* @param networkId The id of the network your provider is connected to
*/
public setProvider(provider: Provider, networkId: number): void {
- this._web3Wrapper.setProvider(provider);
- (this.exchange as any)._invalidateContractInstances();
- (this.exchange as any)._setNetworkId(networkId);
- (this.tokenRegistry as any)._invalidateContractInstance();
- (this.tokenRegistry as any)._setNetworkId(networkId);
- (this.token as any)._invalidateContractInstances();
- (this.token as any)._setNetworkId(networkId);
- (this.proxy as any)._invalidateContractInstance();
- (this.proxy as any)._setNetworkId(networkId);
- (this.etherToken as any)._invalidateContractInstance();
- (this.etherToken as any)._setNetworkId(networkId);
+ this._contractWrappers.setProvider(provider, networkId);
}
/**
* Get the provider instance currently used by 0x.js
* @return Web3 provider instance
*/
public getProvider(): Provider {
- return this._web3Wrapper.getProvider();
+ return this._contractWrappers.getProvider();
}
/**
* Get user Ethereum addresses available through the supplied web3 provider available for sending transactions.
* @return An array of available user Ethereum addresses.
*/
public async getAvailableAddressesAsync(): Promise<string[]> {
- const availableAddresses = await this._web3Wrapper.getAvailableAddressesAsync();
+ // Hack: Get Web3Wrapper from ZeroExContract
+ const web3Wrapper: Web3Wrapper = (this._contractWrappers as any)._web3Wrapper;
+ const availableAddresses = await web3Wrapper.getAvailableAddressesAsync();
return availableAddresses;
}
/**
@@ -223,7 +185,7 @@ export class ZeroEx {
shouldAddPersonalMessagePrefix: boolean,
): Promise<ECSignature> {
return signOrderHashAsync(
- this._web3Wrapper.getProvider(),
+ this._contractWrappers.getProvider(),
orderHash,
signerAddress,
shouldAddPersonalMessagePrefix,
@@ -241,7 +203,9 @@ export class ZeroEx {
pollingIntervalMs = 1000,
timeoutMs?: number,
): Promise<TransactionReceiptWithDecodedLogs> {
- const transactionReceiptWithDecodedLogs = await this._web3Wrapper.awaitTransactionMinedAsync(
+ // Hack: Get Web3Wrapper from ZeroExContract
+ const web3Wrapper: Web3Wrapper = (this._contractWrappers as any)._web3Wrapper;
+ const transactionReceiptWithDecodedLogs = await web3Wrapper.awaitTransactionMinedAsync(
txHash,
pollingIntervalMs,
timeoutMs,
@@ -249,22 +213,17 @@ export class ZeroEx {
return transactionReceiptWithDecodedLogs;
}
/**
- * Instantiates and returns a new OrderStateWatcher instance.
+ * Instantiates and returns a new OrderWatcher instance.
* Defaults to watching the pending state.
* @param config The configuration object. Look up the type for the description.
- * @return An instance of the 0x.js OrderStateWatcher class.
- */
- public createOrderStateWatcher(config?: OrderStateWatcherConfig) {
- return new OrderStateWatcher(this._web3Wrapper, this.token, this.exchange, config);
- }
- /*
- * HACK: `TokenWrapper` needs a token transfer proxy address. `TokenTransferProxy` address is fetched from
- * an `ExchangeWrapper`. `ExchangeWrapper` needs `TokenWrapper` to validate orders, creating a dependency cycle.
- * In order to break this - we create this function here and pass it as a parameter to the `TokenWrapper`
- * and `ProxyWrapper`.
- */
- private async _getTokenTransferProxyAddressAsync(): Promise<string> {
- const tokenTransferProxyAddress = await (this.exchange as any)._getTokenTransferProxyAddressAsync();
- return tokenTransferProxyAddress;
+ * @return An instance of the 0x.js OrderWatcher class.
+ */
+ public async createOrderWatcherAsync(config?: OrderWatcherConfig): Promise<OrderWatcher> {
+ // Hack: Get Web3Wrapper from ZeroExContract
+ const web3Wrapper: Web3Wrapper = (this._contractWrappers as any)._web3Wrapper;
+ const networkId = await web3Wrapper.getNetworkIdAsync();
+ const provider = this._contractWrappers.getProvider();
+ const orderWatcher = new OrderWatcher(provider, networkId, config);
+ return orderWatcher;
}
}
diff --git a/packages/0x.js/src/abstract/balance_and_proxy_allowance_fetcher.ts b/packages/0x.js/src/abstract/balance_and_proxy_allowance_fetcher.ts
deleted file mode 100644
index c357f8447..000000000
--- a/packages/0x.js/src/abstract/balance_and_proxy_allowance_fetcher.ts
+++ /dev/null
@@ -1,6 +0,0 @@
-import { BigNumber } from '@0xproject/utils';
-
-export abstract class BalanceAndProxyAllowanceFetcher {
- public abstract async getBalanceAsync(tokenAddress: string, userAddress: string): Promise<BigNumber>;
- public abstract async getProxyAllowanceAsync(tokenAddress: string, userAddress: string): Promise<BigNumber>;
-}
diff --git a/packages/0x.js/src/abstract/order_filled_cancelled_fetcher.ts b/packages/0x.js/src/abstract/order_filled_cancelled_fetcher.ts
deleted file mode 100644
index 81ae04b9c..000000000
--- a/packages/0x.js/src/abstract/order_filled_cancelled_fetcher.ts
+++ /dev/null
@@ -1,6 +0,0 @@
-import { BigNumber } from '@0xproject/utils';
-
-export abstract class OrderFilledCancelledFetcher {
- public abstract async getFilledTakerAmountAsync(orderHash: string): Promise<BigNumber>;
- public abstract async getCancelledTakerAmountAsync(orderHash: string): Promise<BigNumber>;
-}
diff --git a/packages/0x.js/src/artifacts.ts b/packages/0x.js/src/artifacts.ts
deleted file mode 100644
index a91d9ae1f..000000000
--- a/packages/0x.js/src/artifacts.ts
+++ /dev/null
@@ -1,18 +0,0 @@
-import * as DummyTokenArtifact from './compact_artifacts/DummyToken.json';
-import * as EtherTokenArtifact from './compact_artifacts/EtherToken.json';
-import * as ExchangeArtifact from './compact_artifacts/Exchange.json';
-import * as TokenArtifact from './compact_artifacts/Token.json';
-import * as TokenRegistryArtifact from './compact_artifacts/TokenRegistry.json';
-import * as TokenTransferProxyArtifact from './compact_artifacts/TokenTransferProxy.json';
-import * as ZRXArtifact from './compact_artifacts/ZRX.json';
-import { Artifact } from './types';
-
-export const artifacts = {
- ZRXArtifact: (ZRXArtifact as any) as Artifact,
- DummyTokenArtifact: (DummyTokenArtifact as any) as Artifact,
- TokenArtifact: (TokenArtifact as any) as Artifact,
- ExchangeArtifact: (ExchangeArtifact as any) as Artifact,
- EtherTokenArtifact: (EtherTokenArtifact as any) as Artifact,
- TokenRegistryArtifact: (TokenRegistryArtifact as any) as Artifact,
- TokenTransferProxyArtifact: (TokenTransferProxyArtifact as any) as Artifact,
-};
diff --git a/packages/0x.js/src/contract_wrappers/contract_wrapper.ts b/packages/0x.js/src/contract_wrappers/contract_wrapper.ts
deleted file mode 100644
index 02be2dab3..000000000
--- a/packages/0x.js/src/contract_wrappers/contract_wrapper.ts
+++ /dev/null
@@ -1,202 +0,0 @@
-import { BlockParamLiteral, ContractAbi, FilterObject, LogEntry, LogWithDecodedArgs, RawLog } from '@0xproject/types';
-import { AbiDecoder, intervalUtils } from '@0xproject/utils';
-import { Web3Wrapper } from '@0xproject/web3-wrapper';
-import { Block, BlockAndLogStreamer } from 'ethereumjs-blockstream';
-import * as _ from 'lodash';
-import * as Web3 from 'web3';
-
-import {
- Artifact,
- BlockRange,
- ContractEventArgs,
- ContractEvents,
- EventCallback,
- IndexedFilterValues,
- InternalZeroExError,
- ZeroExError,
-} from '../types';
-import { constants } from '../utils/constants';
-import { filterUtils } from '../utils/filter_utils';
-
-const CONTRACT_NAME_TO_NOT_FOUND_ERROR: {
- [contractName: string]: ZeroExError;
-} = {
- ZRX: ZeroExError.ZRXContractDoesNotExist,
- EtherToken: ZeroExError.EtherTokenContractDoesNotExist,
- Token: ZeroExError.TokenContractDoesNotExist,
- TokenRegistry: ZeroExError.TokenRegistryContractDoesNotExist,
- TokenTransferProxy: ZeroExError.TokenTransferProxyContractDoesNotExist,
- Exchange: ZeroExError.ExchangeContractDoesNotExist,
-};
-
-export class ContractWrapper {
- protected _web3Wrapper: Web3Wrapper;
- protected _networkId: number;
- private _blockAndLogStreamerIfExists?: BlockAndLogStreamer;
- private _blockAndLogStreamIntervalIfExists?: NodeJS.Timer;
- private _filters: { [filterToken: string]: FilterObject };
- private _filterCallbacks: {
- [filterToken: string]: EventCallback<ContractEventArgs>;
- };
- private _onLogAddedSubscriptionToken: string | undefined;
- private _onLogRemovedSubscriptionToken: string | undefined;
- constructor(web3Wrapper: Web3Wrapper, networkId: number) {
- this._web3Wrapper = web3Wrapper;
- this._networkId = networkId;
- this._filters = {};
- this._filterCallbacks = {};
- this._blockAndLogStreamerIfExists = undefined;
- this._onLogAddedSubscriptionToken = undefined;
- this._onLogRemovedSubscriptionToken = undefined;
- }
- protected _unsubscribeAll(): void {
- const filterTokens = _.keys(this._filterCallbacks);
- _.each(filterTokens, filterToken => {
- this._unsubscribe(filterToken);
- });
- }
- protected _unsubscribe(filterToken: string, err?: Error): void {
- if (_.isUndefined(this._filters[filterToken])) {
- throw new Error(ZeroExError.SubscriptionNotFound);
- }
- if (!_.isUndefined(err)) {
- const callback = this._filterCallbacks[filterToken];
- callback(err, undefined);
- }
- delete this._filters[filterToken];
- delete this._filterCallbacks[filterToken];
- if (_.isEmpty(this._filters)) {
- this._stopBlockAndLogStream();
- }
- }
- protected _subscribe<ArgsType extends ContractEventArgs>(
- address: string,
- eventName: ContractEvents,
- indexFilterValues: IndexedFilterValues,
- abi: ContractAbi,
- callback: EventCallback<ArgsType>,
- ): string {
- const filter = filterUtils.getFilter(address, eventName, indexFilterValues, abi);
- if (_.isUndefined(this._blockAndLogStreamerIfExists)) {
- this._startBlockAndLogStream();
- }
- const filterToken = filterUtils.generateUUID();
- this._filters[filterToken] = filter;
- this._filterCallbacks[filterToken] = callback as EventCallback<ContractEventArgs>;
- return filterToken;
- }
- protected async _getLogsAsync<ArgsType extends ContractEventArgs>(
- address: string,
- eventName: ContractEvents,
- blockRange: BlockRange,
- indexFilterValues: IndexedFilterValues,
- abi: ContractAbi,
- ): Promise<Array<LogWithDecodedArgs<ArgsType>>> {
- const filter = filterUtils.getFilter(address, eventName, indexFilterValues, abi, blockRange);
- const logs = await this._web3Wrapper.getLogsAsync(filter);
- const logsWithDecodedArguments = _.map(logs, this._tryToDecodeLogOrNoop.bind(this));
- return logsWithDecodedArguments;
- }
- protected _tryToDecodeLogOrNoop<ArgsType extends ContractEventArgs>(
- log: LogEntry,
- ): LogWithDecodedArgs<ArgsType> | RawLog {
- if (_.isUndefined(this._web3Wrapper.abiDecoder)) {
- throw new Error(InternalZeroExError.NoAbiDecoder);
- }
- const logWithDecodedArgs = this._web3Wrapper.abiDecoder.tryToDecodeLogOrNoop(log);
- return logWithDecodedArgs;
- }
- protected async _getContractAbiAndAddressFromArtifactsAsync(
- artifact: Artifact,
- addressIfExists?: string,
- ): Promise<[ContractAbi, string]> {
- let contractAddress: string;
- if (_.isUndefined(addressIfExists)) {
- if (_.isUndefined(artifact.networks[this._networkId])) {
- throw new Error(ZeroExError.ContractNotDeployedOnNetwork);
- }
- contractAddress = artifact.networks[this._networkId].address.toLowerCase();
- } else {
- contractAddress = addressIfExists;
- }
- const doesContractExist = await this._web3Wrapper.doesContractExistAtAddressAsync(contractAddress);
- if (!doesContractExist) {
- throw new Error(CONTRACT_NAME_TO_NOT_FOUND_ERROR[artifact.contract_name]);
- }
- const abiAndAddress: [ContractAbi, string] = [artifact.abi, contractAddress];
- return abiAndAddress;
- }
- protected _getContractAddress(artifact: Artifact, addressIfExists?: string): string {
- if (_.isUndefined(addressIfExists)) {
- const contractAddress = artifact.networks[this._networkId].address;
- if (_.isUndefined(contractAddress)) {
- throw new Error(ZeroExError.ExchangeContractDoesNotExist);
- }
- return contractAddress;
- } else {
- return addressIfExists;
- }
- }
- private _onLogStateChanged<ArgsType extends ContractEventArgs>(isRemoved: boolean, log: LogEntry): void {
- _.forEach(this._filters, (filter: FilterObject, filterToken: string) => {
- if (filterUtils.matchesFilter(log, filter)) {
- const decodedLog = this._tryToDecodeLogOrNoop(log) as LogWithDecodedArgs<ArgsType>;
- const logEvent = {
- log: decodedLog,
- isRemoved,
- };
- this._filterCallbacks[filterToken](null, logEvent);
- }
- });
- }
- private _startBlockAndLogStream(): void {
- if (!_.isUndefined(this._blockAndLogStreamerIfExists)) {
- throw new Error(ZeroExError.SubscriptionAlreadyPresent);
- }
- this._blockAndLogStreamerIfExists = new BlockAndLogStreamer(
- this._web3Wrapper.getBlockAsync.bind(this._web3Wrapper),
- this._web3Wrapper.getLogsAsync.bind(this._web3Wrapper),
- );
- const catchAllLogFilter = {};
- this._blockAndLogStreamerIfExists.addLogFilter(catchAllLogFilter);
- this._blockAndLogStreamIntervalIfExists = intervalUtils.setAsyncExcludingInterval(
- this._reconcileBlockAsync.bind(this),
- constants.DEFAULT_BLOCK_POLLING_INTERVAL,
- this._onReconcileBlockError.bind(this),
- );
- let isRemoved = false;
- this._onLogAddedSubscriptionToken = this._blockAndLogStreamerIfExists.subscribeToOnLogAdded(
- this._onLogStateChanged.bind(this, isRemoved),
- );
- isRemoved = true;
- this._onLogRemovedSubscriptionToken = this._blockAndLogStreamerIfExists.subscribeToOnLogRemoved(
- this._onLogStateChanged.bind(this, isRemoved),
- );
- }
- private _onReconcileBlockError(err: Error): void {
- const filterTokens = _.keys(this._filterCallbacks);
- _.each(filterTokens, filterToken => {
- this._unsubscribe(filterToken, err);
- });
- }
- private _setNetworkId(networkId: number): void {
- this._networkId = networkId;
- }
- private _stopBlockAndLogStream(): void {
- if (_.isUndefined(this._blockAndLogStreamerIfExists)) {
- throw new Error(ZeroExError.SubscriptionNotFound);
- }
- this._blockAndLogStreamerIfExists.unsubscribeFromOnLogAdded(this._onLogAddedSubscriptionToken as string);
- this._blockAndLogStreamerIfExists.unsubscribeFromOnLogRemoved(this._onLogRemovedSubscriptionToken as string);
- intervalUtils.clearAsyncExcludingInterval(this._blockAndLogStreamIntervalIfExists as NodeJS.Timer);
- delete this._blockAndLogStreamerIfExists;
- }
- private async _reconcileBlockAsync(): Promise<void> {
- const latestBlock = await this._web3Wrapper.getBlockAsync(BlockParamLiteral.Latest);
- // We need to coerce to Block type cause Web3.Block includes types for mempool blocks
- if (!_.isUndefined(this._blockAndLogStreamerIfExists)) {
- // If we clear the interval while fetching the block - this._blockAndLogStreamer will be undefined
- await this._blockAndLogStreamerIfExists.reconcileNewBlock((latestBlock as any) as Block);
- }
- }
-}
diff --git a/packages/0x.js/src/contract_wrappers/ether_token_wrapper.ts b/packages/0x.js/src/contract_wrappers/ether_token_wrapper.ts
deleted file mode 100644
index fd39de34b..000000000
--- a/packages/0x.js/src/contract_wrappers/ether_token_wrapper.ts
+++ /dev/null
@@ -1,204 +0,0 @@
-import { schemas } from '@0xproject/json-schemas';
-import { LogWithDecodedArgs } from '@0xproject/types';
-import { AbiDecoder, BigNumber } from '@0xproject/utils';
-import { Web3Wrapper } from '@0xproject/web3-wrapper';
-import * as _ from 'lodash';
-
-import { artifacts } from '../artifacts';
-import { BlockRange, EventCallback, IndexedFilterValues, TransactionOpts, ZeroExError } from '../types';
-import { assert } from '../utils/assert';
-
-import { ContractWrapper } from './contract_wrapper';
-import { EtherTokenContract, EtherTokenContractEventArgs, EtherTokenEvents } from './generated/ether_token';
-import { TokenWrapper } from './token_wrapper';
-
-/**
- * This class includes all the functionality related to interacting with a wrapped Ether ERC20 token contract.
- * The caller can convert ETH into the equivalent number of wrapped ETH ERC20 tokens and back.
- */
-export class EtherTokenWrapper extends ContractWrapper {
- private _etherTokenContractsByAddress: {
- [address: string]: EtherTokenContract;
- } = {};
- private _tokenWrapper: TokenWrapper;
- constructor(web3Wrapper: Web3Wrapper, networkId: number, tokenWrapper: TokenWrapper) {
- super(web3Wrapper, networkId);
- this._tokenWrapper = tokenWrapper;
- }
- /**
- * Deposit ETH into the Wrapped ETH smart contract and issues the equivalent number of wrapped ETH tokens
- * to the depositor address. These wrapped ETH tokens can be used in 0x trades and are redeemable for 1-to-1
- * for ETH.
- * @param etherTokenAddress EtherToken address you wish to deposit into.
- * @param amountInWei Amount of ETH in Wei the caller wishes to deposit.
- * @param depositor The hex encoded user Ethereum address that would like to make the deposit.
- * @param txOpts Transaction parameters.
- * @return Transaction hash.
- */
- public async depositAsync(
- etherTokenAddress: string,
- amountInWei: BigNumber,
- depositor: string,
- txOpts: TransactionOpts = {},
- ): Promise<string> {
- assert.isETHAddressHex('etherTokenAddress', etherTokenAddress);
- assert.isValidBaseUnitAmount('amountInWei', amountInWei);
- await assert.isSenderAddressAsync('depositor', depositor, this._web3Wrapper);
- const normalizedEtherTokenAddress = etherTokenAddress.toLowerCase();
- const normalizedDepositorAddress = depositor.toLowerCase();
-
- const ethBalanceInWei = await this._web3Wrapper.getBalanceInWeiAsync(normalizedDepositorAddress);
- assert.assert(ethBalanceInWei.gte(amountInWei), ZeroExError.InsufficientEthBalanceForDeposit);
-
- const wethContract = await this._getEtherTokenContractAsync(normalizedEtherTokenAddress);
- const txHash = await wethContract.deposit.sendTransactionAsync({
- from: normalizedDepositorAddress,
- value: amountInWei,
- gas: txOpts.gasLimit,
- gasPrice: txOpts.gasPrice,
- });
- return txHash;
- }
- /**
- * Withdraw ETH to the withdrawer's address from the wrapped ETH smart contract in exchange for the
- * equivalent number of wrapped ETH tokens.
- * @param etherTokenAddress EtherToken address you wish to withdraw from.
- * @param amountInWei Amount of ETH in Wei the caller wishes to withdraw.
- * @param withdrawer The hex encoded user Ethereum address that would like to make the withdrawal.
- * @param txOpts Transaction parameters.
- * @return Transaction hash.
- */
- public async withdrawAsync(
- etherTokenAddress: string,
- amountInWei: BigNumber,
- withdrawer: string,
- txOpts: TransactionOpts = {},
- ): Promise<string> {
- assert.isValidBaseUnitAmount('amountInWei', amountInWei);
- assert.isETHAddressHex('etherTokenAddress', etherTokenAddress);
- await assert.isSenderAddressAsync('withdrawer', withdrawer, this._web3Wrapper);
- const normalizedEtherTokenAddress = etherTokenAddress.toLowerCase();
- const normalizedWithdrawerAddress = withdrawer.toLowerCase();
-
- const WETHBalanceInBaseUnits = await this._tokenWrapper.getBalanceAsync(
- normalizedEtherTokenAddress,
- normalizedWithdrawerAddress,
- );
- assert.assert(WETHBalanceInBaseUnits.gte(amountInWei), ZeroExError.InsufficientWEthBalanceForWithdrawal);
-
- const wethContract = await this._getEtherTokenContractAsync(normalizedEtherTokenAddress);
- const txHash = await wethContract.withdraw.sendTransactionAsync(amountInWei, {
- from: normalizedWithdrawerAddress,
- gas: txOpts.gasLimit,
- gasPrice: txOpts.gasPrice,
- });
- return txHash;
- }
- /**
- * Gets historical logs without creating a subscription
- * @param etherTokenAddress An address of the ether token that emitted the logs.
- * @param eventName The ether token contract event you would like to subscribe to.
- * @param blockRange Block range to get logs from.
- * @param indexFilterValues An object where the keys are indexed args returned by the event and
- * the value is the value you are interested in. E.g `{_owner: aUserAddressHex}`
- * @return Array of logs that match the parameters
- */
- public async getLogsAsync<ArgsType extends EtherTokenContractEventArgs>(
- etherTokenAddress: string,
- eventName: EtherTokenEvents,
- blockRange: BlockRange,
- indexFilterValues: IndexedFilterValues,
- ): Promise<Array<LogWithDecodedArgs<ArgsType>>> {
- assert.isETHAddressHex('etherTokenAddress', etherTokenAddress);
- const normalizedEtherTokenAddress = etherTokenAddress.toLowerCase();
- assert.doesBelongToStringEnum('eventName', eventName, EtherTokenEvents);
- assert.doesConformToSchema('blockRange', blockRange, schemas.blockRangeSchema);
- assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema);
- const logs = await this._getLogsAsync<ArgsType>(
- normalizedEtherTokenAddress,
- eventName,
- blockRange,
- indexFilterValues,
- artifacts.EtherTokenArtifact.abi,
- );
- return logs;
- }
- /**
- * Subscribe to an event type emitted by the Token contract.
- * @param etherTokenAddress The hex encoded address where the ether token is deployed.
- * @param eventName The ether token contract event you would like to subscribe to.
- * @param indexFilterValues An object where the keys are indexed args returned by the event and
- * the value is the value you are interested in. E.g `{_owner: aUserAddressHex}`
- * @param callback Callback that gets called when a log is added/removed
- * @return Subscription token used later to unsubscribe
- */
- public subscribe<ArgsType extends EtherTokenContractEventArgs>(
- etherTokenAddress: string,
- eventName: EtherTokenEvents,
- indexFilterValues: IndexedFilterValues,
- callback: EventCallback<ArgsType>,
- ): string {
- assert.isETHAddressHex('etherTokenAddress', etherTokenAddress);
- const normalizedEtherTokenAddress = etherTokenAddress.toLowerCase();
- assert.doesBelongToStringEnum('eventName', eventName, EtherTokenEvents);
- assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema);
- assert.isFunction('callback', callback);
- const subscriptionToken = this._subscribe<ArgsType>(
- normalizedEtherTokenAddress,
- eventName,
- indexFilterValues,
- artifacts.EtherTokenArtifact.abi,
- callback,
- );
- return subscriptionToken;
- }
- /**
- * Cancel a subscription
- * @param subscriptionToken Subscription token returned by `subscribe()`
- */
- public unsubscribe(subscriptionToken: string): void {
- this._unsubscribe(subscriptionToken);
- }
- /**
- * Cancels all existing subscriptions
- */
- public unsubscribeAll(): void {
- super._unsubscribeAll();
- }
- /**
- * Retrieves the Ethereum address of the EtherToken contract deployed on the network
- * that the user-passed web3 provider is connected to. If it's not Kovan, Ropsten, Rinkeby, Mainnet or TestRPC
- * (networkId: 50), it will return undefined (e.g a private network).
- * @returns The Ethereum address of the EtherToken contract or undefined.
- */
- public getContractAddressIfExists(): string | undefined {
- const networkSpecificArtifact = artifacts.EtherTokenArtifact.networks[this._networkId];
- const contractAddressIfExists = _.isUndefined(networkSpecificArtifact)
- ? undefined
- : networkSpecificArtifact.address;
- return contractAddressIfExists;
- }
- private _invalidateContractInstance(): void {
- this.unsubscribeAll();
- this._etherTokenContractsByAddress = {};
- }
- private async _getEtherTokenContractAsync(etherTokenAddress: string): Promise<EtherTokenContract> {
- let etherTokenContract = this._etherTokenContractsByAddress[etherTokenAddress];
- if (!_.isUndefined(etherTokenContract)) {
- return etherTokenContract;
- }
- const [abi, address] = await this._getContractAbiAndAddressFromArtifactsAsync(
- artifacts.EtherTokenArtifact,
- etherTokenAddress,
- );
- const contractInstance = new EtherTokenContract(
- abi,
- address,
- this._web3Wrapper.getProvider(),
- this._web3Wrapper.getContractDefaults(),
- );
- etherTokenContract = contractInstance;
- this._etherTokenContractsByAddress[etherTokenAddress] = etherTokenContract;
- return etherTokenContract;
- }
-}
diff --git a/packages/0x.js/src/contract_wrappers/exchange_wrapper.ts b/packages/0x.js/src/contract_wrappers/exchange_wrapper.ts
deleted file mode 100644
index 6ddaaaf4f..000000000
--- a/packages/0x.js/src/contract_wrappers/exchange_wrapper.ts
+++ /dev/null
@@ -1,964 +0,0 @@
-import { schemas } from '@0xproject/json-schemas';
-import { getOrderHashHex } from '@0xproject/order-utils';
-import {
- BlockParamLiteral,
- DecodedLogArgs,
- ECSignature,
- LogEntry,
- LogWithDecodedArgs,
- Order,
- SignedOrder,
-} from '@0xproject/types';
-import { AbiDecoder, BigNumber } from '@0xproject/utils';
-import { Web3Wrapper } from '@0xproject/web3-wrapper';
-import * as _ from 'lodash';
-
-import { artifacts } from '../artifacts';
-import { SimpleBalanceAndProxyAllowanceFetcher } from '../fetchers/simple_balance_and_proxy_allowance_fetcher';
-import { SimpleOrderFilledCancelledFetcher } from '../fetchers/simple_order_filled_cancelled_fetcher';
-import {
- BlockRange,
- EventCallback,
- ExchangeContractErrCodes,
- ExchangeContractErrs,
- IndexedFilterValues,
- MethodOpts,
- OrderAddresses,
- OrderCancellationRequest,
- OrderFillRequest,
- OrderState,
- OrderTransactionOpts,
- OrderValues,
- ValidateOrderFillableOpts,
-} from '../types';
-import { assert } from '../utils/assert';
-import { decorators } from '../utils/decorators';
-import { ExchangeTransferSimulator } from '../utils/exchange_transfer_simulator';
-import { OrderStateUtils } from '../utils/order_state_utils';
-import { OrderValidationUtils } from '../utils/order_validation_utils';
-import { utils } from '../utils/utils';
-
-import { ContractWrapper } from './contract_wrapper';
-import {
- ExchangeContract,
- ExchangeContractEventArgs,
- ExchangeEvents,
- LogErrorContractEventArgs,
-} from './generated/exchange';
-import { TokenWrapper } from './token_wrapper';
-const SHOULD_VALIDATE_BY_DEFAULT = true;
-
-interface ExchangeContractErrCodesToMsgs {
- [exchangeContractErrCodes: number]: string;
-}
-
-/**
- * This class includes all the functionality related to calling methods and subscribing to
- * events of the 0x Exchange smart contract.
- */
-export class ExchangeWrapper extends ContractWrapper {
- private _exchangeContractIfExists?: ExchangeContract;
- private _orderValidationUtils: OrderValidationUtils;
- private _tokenWrapper: TokenWrapper;
- private _exchangeContractErrCodesToMsg: ExchangeContractErrCodesToMsgs = {
- [ExchangeContractErrCodes.ERROR_FILL_EXPIRED]: ExchangeContractErrs.OrderFillExpired,
- [ExchangeContractErrCodes.ERROR_CANCEL_EXPIRED]: ExchangeContractErrs.OrderFillExpired,
- [ExchangeContractErrCodes.ERROR_FILL_NO_VALUE]: ExchangeContractErrs.OrderRemainingFillAmountZero,
- [ExchangeContractErrCodes.ERROR_CANCEL_NO_VALUE]: ExchangeContractErrs.OrderRemainingFillAmountZero,
- [ExchangeContractErrCodes.ERROR_FILL_TRUNCATION]: ExchangeContractErrs.OrderFillRoundingError,
- [ExchangeContractErrCodes.ERROR_FILL_BALANCE_ALLOWANCE]: ExchangeContractErrs.FillBalanceAllowanceError,
- };
- private _contractAddressIfExists?: string;
- private _zrxContractAddressIfExists?: string;
- private static _getOrderAddressesAndValues(order: Order): [OrderAddresses, OrderValues] {
- const orderAddresses: OrderAddresses = [
- order.maker,
- order.taker,
- order.makerTokenAddress,
- order.takerTokenAddress,
- order.feeRecipient,
- ];
- const orderValues: OrderValues = [
- order.makerTokenAmount,
- order.takerTokenAmount,
- order.makerFee,
- order.takerFee,
- order.expirationUnixTimestampSec,
- order.salt,
- ];
- return [orderAddresses, orderValues];
- }
- constructor(
- web3Wrapper: Web3Wrapper,
- networkId: number,
- tokenWrapper: TokenWrapper,
- contractAddressIfExists?: string,
- zrxContractAddressIfExists?: string,
- ) {
- super(web3Wrapper, networkId);
- this._tokenWrapper = tokenWrapper;
- this._orderValidationUtils = new OrderValidationUtils(this);
- this._contractAddressIfExists = contractAddressIfExists;
- this._zrxContractAddressIfExists = zrxContractAddressIfExists;
- }
- /**
- * Returns the unavailable takerAmount of an order. Unavailable amount is defined as the total
- * amount that has been filled or cancelled. The remaining takerAmount can be calculated by
- * subtracting the unavailable amount from the total order takerAmount.
- * @param orderHash The hex encoded orderHash for which you would like to retrieve the
- * unavailable takerAmount.
- * @param methodOpts Optional arguments this method accepts.
- * @return The amount of the order (in taker tokens) that has either been filled or cancelled.
- */
- public async getUnavailableTakerAmountAsync(orderHash: string, methodOpts?: MethodOpts): Promise<BigNumber> {
- assert.doesConformToSchema('orderHash', orderHash, schemas.orderHashSchema);
-
- const exchangeContract = await this._getExchangeContractAsync();
- const defaultBlock = _.isUndefined(methodOpts) ? undefined : methodOpts.defaultBlock;
- const txData = {};
- let unavailableTakerTokenAmount = await exchangeContract.getUnavailableTakerTokenAmount.callAsync(
- orderHash,
- txData,
- defaultBlock,
- );
- // Wrap BigNumbers returned from web3 with our own (later) version of BigNumber
- unavailableTakerTokenAmount = new BigNumber(unavailableTakerTokenAmount);
- return unavailableTakerTokenAmount;
- }
- /**
- * Retrieve the takerAmount of an order that has already been filled.
- * @param orderHash The hex encoded orderHash for which you would like to retrieve the filled takerAmount.
- * @param methodOpts Optional arguments this method accepts.
- * @return The amount of the order (in taker tokens) that has already been filled.
- */
- public async getFilledTakerAmountAsync(orderHash: string, methodOpts?: MethodOpts): Promise<BigNumber> {
- assert.doesConformToSchema('orderHash', orderHash, schemas.orderHashSchema);
-
- const exchangeContract = await this._getExchangeContractAsync();
- const defaultBlock = _.isUndefined(methodOpts) ? undefined : methodOpts.defaultBlock;
- const txData = {};
- let fillAmountInBaseUnits = await exchangeContract.filled.callAsync(orderHash, txData, defaultBlock);
- // Wrap BigNumbers returned from web3 with our own (later) version of BigNumber
- fillAmountInBaseUnits = new BigNumber(fillAmountInBaseUnits);
- return fillAmountInBaseUnits;
- }
- /**
- * Retrieve the takerAmount of an order that has been cancelled.
- * @param orderHash The hex encoded orderHash for which you would like to retrieve the
- * cancelled takerAmount.
- * @param methodOpts Optional arguments this method accepts.
- * @return The amount of the order (in taker tokens) that has been cancelled.
- */
- public async getCancelledTakerAmountAsync(orderHash: string, methodOpts?: MethodOpts): Promise<BigNumber> {
- assert.doesConformToSchema('orderHash', orderHash, schemas.orderHashSchema);
-
- const exchangeContract = await this._getExchangeContractAsync();
- const defaultBlock = _.isUndefined(methodOpts) ? undefined : methodOpts.defaultBlock;
- const txData = {};
- let cancelledAmountInBaseUnits = await exchangeContract.cancelled.callAsync(orderHash, txData, defaultBlock);
- // Wrap BigNumbers returned from web3 with our own (later) version of BigNumber
- cancelledAmountInBaseUnits = new BigNumber(cancelledAmountInBaseUnits);
- return cancelledAmountInBaseUnits;
- }
- /**
- * Fills a signed order with an amount denominated in baseUnits of the taker token.
- * Since the order in which transactions are included in the next block is indeterminate, race-conditions
- * could arise where a users balance or allowance changes before the fillOrder executes. Because of this,
- * we allow you to specify `shouldThrowOnInsufficientBalanceOrAllowance`.
- * If false, the smart contract will not throw if the parties
- * do not have sufficient balances/allowances, preserving gas costs. Setting it to true forgoes this check
- * and causes the smart contract to throw (using all the gas supplied) instead.
- * @param signedOrder An object that conforms to the SignedOrder interface.
- * @param fillTakerTokenAmount The amount of the order (in taker tokens baseUnits) that
- * you wish to fill.
- * @param shouldThrowOnInsufficientBalanceOrAllowance Whether or not you wish for the contract call to throw
- * if upon execution the tokens cannot be transferred.
- * @param takerAddress The user Ethereum address who would like to fill this order.
- * Must be available via the supplied Provider
- * passed to 0x.js.
- * @param orderTransactionOpts Optional arguments this method accepts.
- * @return Transaction hash.
- */
- @decorators.asyncZeroExErrorHandler
- public async fillOrderAsync(
- signedOrder: SignedOrder,
- fillTakerTokenAmount: BigNumber,
- shouldThrowOnInsufficientBalanceOrAllowance: boolean,
- takerAddress: string,
- orderTransactionOpts: OrderTransactionOpts = {},
- ): Promise<string> {
- assert.doesConformToSchema('signedOrder', signedOrder, schemas.signedOrderSchema);
- assert.isValidBaseUnitAmount('fillTakerTokenAmount', fillTakerTokenAmount);
- assert.isBoolean('shouldThrowOnInsufficientBalanceOrAllowance', shouldThrowOnInsufficientBalanceOrAllowance);
- await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper);
- const normalizedTakerAddress = takerAddress.toLowerCase();
-
- const exchangeInstance = await this._getExchangeContractAsync();
- const shouldValidate = _.isUndefined(orderTransactionOpts.shouldValidate)
- ? SHOULD_VALIDATE_BY_DEFAULT
- : orderTransactionOpts.shouldValidate;
- if (shouldValidate) {
- const zrxTokenAddress = this.getZRXTokenAddress();
- const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest);
- await this._orderValidationUtils.validateFillOrderThrowIfInvalidAsync(
- exchangeTradeEmulator,
- signedOrder,
- fillTakerTokenAmount,
- normalizedTakerAddress,
- zrxTokenAddress,
- );
- }
-
- const [orderAddresses, orderValues] = ExchangeWrapper._getOrderAddressesAndValues(signedOrder);
-
- const txHash: string = await exchangeInstance.fillOrder.sendTransactionAsync(
- orderAddresses,
- orderValues,
- fillTakerTokenAmount,
- shouldThrowOnInsufficientBalanceOrAllowance,
- signedOrder.ecSignature.v,
- signedOrder.ecSignature.r,
- signedOrder.ecSignature.s,
- {
- from: normalizedTakerAddress,
- gas: orderTransactionOpts.gasLimit,
- gasPrice: orderTransactionOpts.gasPrice,
- },
- );
- return txHash;
- }
- /**
- * Sequentially and atomically fills signedOrders up to the specified takerTokenFillAmount.
- * If the fill amount is reached - it succeeds and does not fill the rest of the orders.
- * If fill amount is not reached - it fills as much of the fill amount as possible and succeeds.
- * @param signedOrders The array of signedOrders that you would like to fill until
- * takerTokenFillAmount is reached.
- * @param fillTakerTokenAmount The total amount of the takerTokens you would like to fill.
- * @param shouldThrowOnInsufficientBalanceOrAllowance Whether or not you wish for the contract call to throw if
- * upon execution any of the tokens cannot be transferred.
- * If set to false, the call will continue to fill subsequent
- * signedOrders even when some cannot be filled.
- * @param takerAddress The user Ethereum address who would like to fill these
- * orders. Must be available via the supplied Provider
- * passed to 0x.js.
- * @param orderTransactionOpts Optional arguments this method accepts.
- * @return Transaction hash.
- */
- @decorators.asyncZeroExErrorHandler
- public async fillOrdersUpToAsync(
- signedOrders: SignedOrder[],
- fillTakerTokenAmount: BigNumber,
- shouldThrowOnInsufficientBalanceOrAllowance: boolean,
- takerAddress: string,
- orderTransactionOpts: OrderTransactionOpts = {},
- ): Promise<string> {
- assert.doesConformToSchema('signedOrders', signedOrders, schemas.signedOrdersSchema);
- const takerTokenAddresses = _.map(signedOrders, signedOrder => signedOrder.takerTokenAddress);
- assert.hasAtMostOneUniqueValue(
- takerTokenAddresses,
- ExchangeContractErrs.MultipleTakerTokensInFillUpToDisallowed,
- );
- const exchangeContractAddresses = _.map(signedOrders, signedOrder => signedOrder.exchangeContractAddress);
- assert.hasAtMostOneUniqueValue(
- exchangeContractAddresses,
- ExchangeContractErrs.BatchOrdersMustHaveSameExchangeAddress,
- );
- assert.isValidBaseUnitAmount('fillTakerTokenAmount', fillTakerTokenAmount);
- assert.isBoolean('shouldThrowOnInsufficientBalanceOrAllowance', shouldThrowOnInsufficientBalanceOrAllowance);
- await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper);
- const normalizedTakerAddress = takerAddress.toLowerCase();
-
- const shouldValidate = _.isUndefined(orderTransactionOpts.shouldValidate)
- ? SHOULD_VALIDATE_BY_DEFAULT
- : orderTransactionOpts.shouldValidate;
- if (shouldValidate) {
- let filledTakerTokenAmount = new BigNumber(0);
- const zrxTokenAddress = this.getZRXTokenAddress();
- const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest);
- for (const signedOrder of signedOrders) {
- const singleFilledTakerTokenAmount = await this._orderValidationUtils.validateFillOrderThrowIfInvalidAsync(
- exchangeTradeEmulator,
- signedOrder,
- fillTakerTokenAmount.minus(filledTakerTokenAmount),
- normalizedTakerAddress,
- zrxTokenAddress,
- );
- filledTakerTokenAmount = filledTakerTokenAmount.plus(singleFilledTakerTokenAmount);
- if (filledTakerTokenAmount.eq(fillTakerTokenAmount)) {
- break;
- }
- }
- }
-
- if (_.isEmpty(signedOrders)) {
- throw new Error(ExchangeContractErrs.BatchOrdersMustHaveAtLeastOneItem);
- }
-
- const orderAddressesValuesAndSignatureArray = _.map(signedOrders, signedOrder => {
- return [
- ...ExchangeWrapper._getOrderAddressesAndValues(signedOrder),
- signedOrder.ecSignature.v,
- signedOrder.ecSignature.r,
- signedOrder.ecSignature.s,
- ];
- });
- // We use _.unzip<any> because _.unzip doesn't type check if values have different types :'(
- const [orderAddressesArray, orderValuesArray, vArray, rArray, sArray] = _.unzip<any>(
- orderAddressesValuesAndSignatureArray,
- );
-
- const exchangeInstance = await this._getExchangeContractAsync();
- const txHash = await exchangeInstance.fillOrdersUpTo.sendTransactionAsync(
- orderAddressesArray,
- orderValuesArray,
- fillTakerTokenAmount,
- shouldThrowOnInsufficientBalanceOrAllowance,
- vArray,
- rArray,
- sArray,
- {
- from: normalizedTakerAddress,
- gas: orderTransactionOpts.gasLimit,
- gasPrice: orderTransactionOpts.gasPrice,
- },
- );
- return txHash;
- }
- /**
- * Batch version of fillOrderAsync.
- * Executes multiple fills atomically in a single transaction.
- * If shouldThrowOnInsufficientBalanceOrAllowance is set to false, it will continue filling subsequent orders even
- * when earlier ones fail.
- * When shouldThrowOnInsufficientBalanceOrAllowance is set to true, if any fill fails, the entire batch fails.
- * @param orderFillRequests An array of objects that conform to the
- * OrderFillRequest interface.
- * @param shouldThrowOnInsufficientBalanceOrAllowance Whether or not you wish for the contract call to throw
- * if upon execution any of the tokens cannot be
- * transferred. If set to false, the call will continue to
- * fill subsequent signedOrders even when some
- * cannot be filled.
- * @param takerAddress The user Ethereum address who would like to fill
- * these orders. Must be available via the supplied
- * Provider passed to 0x.js.
- * @param orderTransactionOpts Optional arguments this method accepts.
- * @return Transaction hash.
- */
- @decorators.asyncZeroExErrorHandler
- public async batchFillOrdersAsync(
- orderFillRequests: OrderFillRequest[],
- shouldThrowOnInsufficientBalanceOrAllowance: boolean,
- takerAddress: string,
- orderTransactionOpts: OrderTransactionOpts = {},
- ): Promise<string> {
- assert.doesConformToSchema('orderFillRequests', orderFillRequests, schemas.orderFillRequestsSchema);
- const exchangeContractAddresses = _.map(
- orderFillRequests,
- orderFillRequest => orderFillRequest.signedOrder.exchangeContractAddress,
- );
- assert.hasAtMostOneUniqueValue(
- exchangeContractAddresses,
- ExchangeContractErrs.BatchOrdersMustHaveSameExchangeAddress,
- );
- assert.isBoolean('shouldThrowOnInsufficientBalanceOrAllowance', shouldThrowOnInsufficientBalanceOrAllowance);
- await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper);
- const normalizedTakerAddress = takerAddress.toLowerCase();
- const shouldValidate = _.isUndefined(orderTransactionOpts.shouldValidate)
- ? SHOULD_VALIDATE_BY_DEFAULT
- : orderTransactionOpts.shouldValidate;
- if (shouldValidate) {
- const zrxTokenAddress = this.getZRXTokenAddress();
- const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest);
- for (const orderFillRequest of orderFillRequests) {
- await this._orderValidationUtils.validateFillOrderThrowIfInvalidAsync(
- exchangeTradeEmulator,
- orderFillRequest.signedOrder,
- orderFillRequest.takerTokenFillAmount,
- normalizedTakerAddress,
- zrxTokenAddress,
- );
- }
- }
- if (_.isEmpty(orderFillRequests)) {
- throw new Error(ExchangeContractErrs.BatchOrdersMustHaveAtLeastOneItem);
- }
-
- const orderAddressesValuesAmountsAndSignatureArray = _.map(orderFillRequests, orderFillRequest => {
- return [
- ...ExchangeWrapper._getOrderAddressesAndValues(orderFillRequest.signedOrder),
- orderFillRequest.takerTokenFillAmount,
- orderFillRequest.signedOrder.ecSignature.v,
- orderFillRequest.signedOrder.ecSignature.r,
- orderFillRequest.signedOrder.ecSignature.s,
- ];
- });
- // We use _.unzip<any> because _.unzip doesn't type check if values have different types :'(
- const [orderAddressesArray, orderValuesArray, fillTakerTokenAmounts, vArray, rArray, sArray] = _.unzip<any>(
- orderAddressesValuesAmountsAndSignatureArray,
- );
-
- const exchangeInstance = await this._getExchangeContractAsync();
- const txHash = await exchangeInstance.batchFillOrders.sendTransactionAsync(
- orderAddressesArray,
- orderValuesArray,
- fillTakerTokenAmounts,
- shouldThrowOnInsufficientBalanceOrAllowance,
- vArray,
- rArray,
- sArray,
- {
- from: normalizedTakerAddress,
- gas: orderTransactionOpts.gasLimit,
- gasPrice: orderTransactionOpts.gasPrice,
- },
- );
- return txHash;
- }
- /**
- * Attempts to fill a specific amount of an order. If the entire amount specified cannot be filled,
- * the fill order is abandoned.
- * @param signedOrder An object that conforms to the SignedOrder interface. The
- * signedOrder you wish to fill.
- * @param fillTakerTokenAmount The total amount of the takerTokens you would like to fill.
- * @param takerAddress The user Ethereum address who would like to fill this order.
- * Must be available via the supplied Provider passed to 0x.js.
- * @param orderTransactionOpts Optional arguments this method accepts.
- * @return Transaction hash.
- */
- @decorators.asyncZeroExErrorHandler
- public async fillOrKillOrderAsync(
- signedOrder: SignedOrder,
- fillTakerTokenAmount: BigNumber,
- takerAddress: string,
- orderTransactionOpts: OrderTransactionOpts = {},
- ): Promise<string> {
- assert.doesConformToSchema('signedOrder', signedOrder, schemas.signedOrderSchema);
- assert.isValidBaseUnitAmount('fillTakerTokenAmount', fillTakerTokenAmount);
- await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper);
- const normalizedTakerAddress = takerAddress.toLowerCase();
-
- const exchangeInstance = await this._getExchangeContractAsync();
-
- const shouldValidate = _.isUndefined(orderTransactionOpts.shouldValidate)
- ? SHOULD_VALIDATE_BY_DEFAULT
- : orderTransactionOpts.shouldValidate;
- if (shouldValidate) {
- const zrxTokenAddress = this.getZRXTokenAddress();
- const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest);
- await this._orderValidationUtils.validateFillOrKillOrderThrowIfInvalidAsync(
- exchangeTradeEmulator,
- signedOrder,
- fillTakerTokenAmount,
- normalizedTakerAddress,
- zrxTokenAddress,
- );
- }
-
- const [orderAddresses, orderValues] = ExchangeWrapper._getOrderAddressesAndValues(signedOrder);
- const txHash = await exchangeInstance.fillOrKillOrder.sendTransactionAsync(
- orderAddresses,
- orderValues,
- fillTakerTokenAmount,
- signedOrder.ecSignature.v,
- signedOrder.ecSignature.r,
- signedOrder.ecSignature.s,
- {
- from: normalizedTakerAddress,
- gas: orderTransactionOpts.gasLimit,
- gasPrice: orderTransactionOpts.gasPrice,
- },
- );
- return txHash;
- }
- /**
- * Batch version of fillOrKill. Allows a taker to specify a batch of orders that will either be atomically
- * filled (each to the specified fillAmount) or aborted.
- * @param orderFillRequests An array of objects that conform to the OrderFillRequest interface.
- * @param takerAddress The user Ethereum address who would like to fill there orders.
- * Must be available via the supplied Provider passed to 0x.js.
- * @param orderTransactionOpts Optional arguments this method accepts.
- * @return Transaction hash.
- */
- @decorators.asyncZeroExErrorHandler
- public async batchFillOrKillAsync(
- orderFillRequests: OrderFillRequest[],
- takerAddress: string,
- orderTransactionOpts: OrderTransactionOpts = {},
- ): Promise<string> {
- assert.doesConformToSchema('orderFillRequests', orderFillRequests, schemas.orderFillRequestsSchema);
- const exchangeContractAddresses = _.map(
- orderFillRequests,
- orderFillRequest => orderFillRequest.signedOrder.exchangeContractAddress,
- );
- assert.hasAtMostOneUniqueValue(
- exchangeContractAddresses,
- ExchangeContractErrs.BatchOrdersMustHaveSameExchangeAddress,
- );
- await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper);
- const normalizedTakerAddress = takerAddress.toLowerCase();
- if (_.isEmpty(orderFillRequests)) {
- throw new Error(ExchangeContractErrs.BatchOrdersMustHaveAtLeastOneItem);
- }
- const exchangeInstance = await this._getExchangeContractAsync();
-
- const shouldValidate = _.isUndefined(orderTransactionOpts.shouldValidate)
- ? SHOULD_VALIDATE_BY_DEFAULT
- : orderTransactionOpts.shouldValidate;
- if (shouldValidate) {
- const zrxTokenAddress = this.getZRXTokenAddress();
- const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest);
- for (const orderFillRequest of orderFillRequests) {
- await this._orderValidationUtils.validateFillOrKillOrderThrowIfInvalidAsync(
- exchangeTradeEmulator,
- orderFillRequest.signedOrder,
- orderFillRequest.takerTokenFillAmount,
- normalizedTakerAddress,
- zrxTokenAddress,
- );
- }
- }
-
- const orderAddressesValuesAndTakerTokenFillAmounts = _.map(orderFillRequests, request => {
- return [
- ...ExchangeWrapper._getOrderAddressesAndValues(request.signedOrder),
- request.takerTokenFillAmount,
- request.signedOrder.ecSignature.v,
- request.signedOrder.ecSignature.r,
- request.signedOrder.ecSignature.s,
- ];
- });
-
- // We use _.unzip<any> because _.unzip doesn't type check if values have different types :'(
- const [orderAddresses, orderValues, fillTakerTokenAmounts, vParams, rParams, sParams] = _.unzip<any>(
- orderAddressesValuesAndTakerTokenFillAmounts,
- );
- const txHash = await exchangeInstance.batchFillOrKillOrders.sendTransactionAsync(
- orderAddresses,
- orderValues,
- fillTakerTokenAmounts,
- vParams,
- rParams,
- sParams,
- {
- from: normalizedTakerAddress,
- gas: orderTransactionOpts.gasLimit,
- gasPrice: orderTransactionOpts.gasPrice,
- },
- );
- return txHash;
- }
- /**
- * Cancel a given fill amount of an order. Cancellations are cumulative.
- * @param order An object that conforms to the Order or SignedOrder interface.
- * The order you would like to cancel.
- * @param cancelTakerTokenAmount The amount (specified in taker tokens) that you would like to cancel.
- * @param transactionOpts Optional arguments this method accepts.
- * @return Transaction hash.
- */
- @decorators.asyncZeroExErrorHandler
- public async cancelOrderAsync(
- order: Order | SignedOrder,
- cancelTakerTokenAmount: BigNumber,
- orderTransactionOpts: OrderTransactionOpts = {},
- ): Promise<string> {
- assert.doesConformToSchema('order', order, schemas.orderSchema);
- assert.isValidBaseUnitAmount('takerTokenCancelAmount', cancelTakerTokenAmount);
- await assert.isSenderAddressAsync('order.maker', order.maker, this._web3Wrapper);
- const normalizedMakerAddress = order.maker.toLowerCase();
-
- const exchangeInstance = await this._getExchangeContractAsync();
-
- const shouldValidate = _.isUndefined(orderTransactionOpts.shouldValidate)
- ? SHOULD_VALIDATE_BY_DEFAULT
- : orderTransactionOpts.shouldValidate;
- if (shouldValidate) {
- const orderHash = getOrderHashHex(order);
- const unavailableTakerTokenAmount = await this.getUnavailableTakerAmountAsync(orderHash);
- OrderValidationUtils.validateCancelOrderThrowIfInvalid(
- order,
- cancelTakerTokenAmount,
- unavailableTakerTokenAmount,
- );
- }
-
- const [orderAddresses, orderValues] = ExchangeWrapper._getOrderAddressesAndValues(order);
- const txHash = await exchangeInstance.cancelOrder.sendTransactionAsync(
- orderAddresses,
- orderValues,
- cancelTakerTokenAmount,
- {
- from: normalizedMakerAddress,
- gas: orderTransactionOpts.gasLimit,
- gasPrice: orderTransactionOpts.gasPrice,
- },
- );
- return txHash;
- }
- /**
- * Batch version of cancelOrderAsync. Atomically cancels multiple orders in a single transaction.
- * All orders must be from the same maker.
- * @param orderCancellationRequests An array of objects that conform to the OrderCancellationRequest
- * interface.
- * @param transactionOpts Optional arguments this method accepts.
- * @return Transaction hash.
- */
- @decorators.asyncZeroExErrorHandler
- public async batchCancelOrdersAsync(
- orderCancellationRequests: OrderCancellationRequest[],
- orderTransactionOpts: OrderTransactionOpts = {},
- ): Promise<string> {
- assert.doesConformToSchema(
- 'orderCancellationRequests',
- orderCancellationRequests,
- schemas.orderCancellationRequestsSchema,
- );
- const exchangeContractAddresses = _.map(
- orderCancellationRequests,
- orderCancellationRequest => orderCancellationRequest.order.exchangeContractAddress,
- );
- assert.hasAtMostOneUniqueValue(
- exchangeContractAddresses,
- ExchangeContractErrs.BatchOrdersMustHaveSameExchangeAddress,
- );
- const makers = _.map(orderCancellationRequests, cancellationRequest => cancellationRequest.order.maker);
- assert.hasAtMostOneUniqueValue(makers, ExchangeContractErrs.MultipleMakersInSingleCancelBatchDisallowed);
- const maker = makers[0];
- await assert.isSenderAddressAsync('maker', maker, this._web3Wrapper);
- const normalizedMakerAddress = maker.toLowerCase();
-
- const shouldValidate = _.isUndefined(orderTransactionOpts.shouldValidate)
- ? SHOULD_VALIDATE_BY_DEFAULT
- : orderTransactionOpts.shouldValidate;
- if (shouldValidate) {
- for (const orderCancellationRequest of orderCancellationRequests) {
- const orderHash = getOrderHashHex(orderCancellationRequest.order);
- const unavailableTakerTokenAmount = await this.getUnavailableTakerAmountAsync(orderHash);
- OrderValidationUtils.validateCancelOrderThrowIfInvalid(
- orderCancellationRequest.order,
- orderCancellationRequest.takerTokenCancelAmount,
- unavailableTakerTokenAmount,
- );
- }
- }
- if (_.isEmpty(orderCancellationRequests)) {
- throw new Error(ExchangeContractErrs.BatchOrdersMustHaveAtLeastOneItem);
- }
- const exchangeInstance = await this._getExchangeContractAsync();
- const orderAddressesValuesAndTakerTokenCancelAmounts = _.map(orderCancellationRequests, cancellationRequest => {
- return [
- ...ExchangeWrapper._getOrderAddressesAndValues(cancellationRequest.order),
- cancellationRequest.takerTokenCancelAmount,
- ];
- });
- // We use _.unzip<any> because _.unzip doesn't type check if values have different types :'(
- const [orderAddresses, orderValues, cancelTakerTokenAmounts] = _.unzip<any>(
- orderAddressesValuesAndTakerTokenCancelAmounts,
- );
- const txHash = await exchangeInstance.batchCancelOrders.sendTransactionAsync(
- orderAddresses,
- orderValues,
- cancelTakerTokenAmounts,
- {
- from: normalizedMakerAddress,
- gas: orderTransactionOpts.gasLimit,
- gasPrice: orderTransactionOpts.gasPrice,
- },
- );
- return txHash;
- }
- /**
- * Subscribe to an event type emitted by the Exchange contract.
- * @param eventName The exchange contract event you would like to subscribe to.
- * @param indexFilterValues An object where the keys are indexed args returned by the event and
- * the value is the value you are interested in. E.g `{maker: aUserAddressHex}`
- * @param callback Callback that gets called when a log is added/removed
- * @return Subscription token used later to unsubscribe
- */
- public subscribe<ArgsType extends ExchangeContractEventArgs>(
- eventName: ExchangeEvents,
- indexFilterValues: IndexedFilterValues,
- callback: EventCallback<ArgsType>,
- ): string {
- assert.doesBelongToStringEnum('eventName', eventName, ExchangeEvents);
- assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema);
- assert.isFunction('callback', callback);
- const exchangeContractAddress = this.getContractAddress();
- const subscriptionToken = this._subscribe<ArgsType>(
- exchangeContractAddress,
- eventName,
- indexFilterValues,
- artifacts.ExchangeArtifact.abi,
- callback,
- );
- return subscriptionToken;
- }
- /**
- * Cancel a subscription
- * @param subscriptionToken Subscription token returned by `subscribe()`
- */
- public unsubscribe(subscriptionToken: string): void {
- this._unsubscribe(subscriptionToken);
- }
- /**
- * Cancels all existing subscriptions
- */
- public unsubscribeAll(): void {
- super._unsubscribeAll();
- }
- /**
- * Gets historical logs without creating a subscription
- * @param eventName The exchange contract event you would like to subscribe to.
- * @param blockRange Block range to get logs from.
- * @param indexFilterValues An object where the keys are indexed args returned by the event and
- * the value is the value you are interested in. E.g `{_from: aUserAddressHex}`
- * @return Array of logs that match the parameters
- */
- public async getLogsAsync<ArgsType extends ExchangeContractEventArgs>(
- eventName: ExchangeEvents,
- blockRange: BlockRange,
- indexFilterValues: IndexedFilterValues,
- ): Promise<Array<LogWithDecodedArgs<ArgsType>>> {
- assert.doesBelongToStringEnum('eventName', eventName, ExchangeEvents);
- assert.doesConformToSchema('blockRange', blockRange, schemas.blockRangeSchema);
- assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema);
- const exchangeContractAddress = this.getContractAddress();
- const logs = await this._getLogsAsync<ArgsType>(
- exchangeContractAddress,
- eventName,
- blockRange,
- indexFilterValues,
- artifacts.ExchangeArtifact.abi,
- );
- return logs;
- }
- /**
- * Retrieves the Ethereum address of the Exchange contract deployed on the network
- * that the user-passed web3 provider is connected to.
- * @returns The Ethereum address of the Exchange contract being used.
- */
- public getContractAddress(): string {
- const contractAddress = this._getContractAddress(artifacts.ExchangeArtifact, this._contractAddressIfExists);
- return contractAddress;
- }
- /**
- * Checks if order is still fillable and throws an error otherwise. Useful for orderbook
- * pruning where you want to remove stale orders without knowing who the taker will be.
- * @param signedOrder An object that conforms to the SignedOrder interface. The
- * signedOrder you wish to validate.
- * @param opts An object that conforms to the ValidateOrderFillableOpts
- * interface. Allows specifying a specific fillTakerTokenAmount
- * to validate for.
- */
- public async validateOrderFillableOrThrowAsync(
- signedOrder: SignedOrder,
- opts?: ValidateOrderFillableOpts,
- ): Promise<void> {
- assert.doesConformToSchema('signedOrder', signedOrder, schemas.signedOrderSchema);
- const zrxTokenAddress = this.getZRXTokenAddress();
- const expectedFillTakerTokenAmount = !_.isUndefined(opts) ? opts.expectedFillTakerTokenAmount : undefined;
- const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest);
- await this._orderValidationUtils.validateOrderFillableOrThrowAsync(
- exchangeTradeEmulator,
- signedOrder,
- zrxTokenAddress,
- expectedFillTakerTokenAmount,
- );
- }
- /**
- * Checks if order fill will succeed and throws an error otherwise.
- * @param signedOrder An object that conforms to the SignedOrder interface. The
- * signedOrder you wish to fill.
- * @param fillTakerTokenAmount The total amount of the takerTokens you would like to fill.
- * @param takerAddress The user Ethereum address who would like to fill this order.
- * Must be available via the supplied Provider passed to 0x.js.
- */
- public async validateFillOrderThrowIfInvalidAsync(
- signedOrder: SignedOrder,
- fillTakerTokenAmount: BigNumber,
- takerAddress: string,
- ): Promise<void> {
- assert.doesConformToSchema('signedOrder', signedOrder, schemas.signedOrderSchema);
- assert.isValidBaseUnitAmount('fillTakerTokenAmount', fillTakerTokenAmount);
- await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper);
- const normalizedTakerAddress = takerAddress.toLowerCase();
- const zrxTokenAddress = this.getZRXTokenAddress();
- const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest);
- await this._orderValidationUtils.validateFillOrderThrowIfInvalidAsync(
- exchangeTradeEmulator,
- signedOrder,
- fillTakerTokenAmount,
- normalizedTakerAddress,
- zrxTokenAddress,
- );
- }
- /**
- * Checks if cancelling a given order will succeed and throws an informative error if it won't.
- * @param order An object that conforms to the Order or SignedOrder interface.
- * The order you would like to cancel.
- * @param cancelTakerTokenAmount The amount (specified in taker tokens) that you would like to cancel.
- */
- public async validateCancelOrderThrowIfInvalidAsync(
- order: Order,
- cancelTakerTokenAmount: BigNumber,
- ): Promise<void> {
- assert.doesConformToSchema('order', order, schemas.orderSchema);
- assert.isValidBaseUnitAmount('cancelTakerTokenAmount', cancelTakerTokenAmount);
- const orderHash = getOrderHashHex(order);
- const unavailableTakerTokenAmount = await this.getUnavailableTakerAmountAsync(orderHash);
- OrderValidationUtils.validateCancelOrderThrowIfInvalid(
- order,
- cancelTakerTokenAmount,
- unavailableTakerTokenAmount,
- );
- }
- /**
- * Checks if calling fillOrKill on a given order will succeed and throws an informative error if it won't.
- * @param signedOrder An object that conforms to the SignedOrder interface. The
- * signedOrder you wish to fill.
- * @param fillTakerTokenAmount The total amount of the takerTokens you would like to fill.
- * @param takerAddress The user Ethereum address who would like to fill this order.
- * Must be available via the supplied Provider passed to 0x.js.
- */
- public async validateFillOrKillOrderThrowIfInvalidAsync(
- signedOrder: SignedOrder,
- fillTakerTokenAmount: BigNumber,
- takerAddress: string,
- ): Promise<void> {
- assert.doesConformToSchema('signedOrder', signedOrder, schemas.signedOrderSchema);
- assert.isValidBaseUnitAmount('fillTakerTokenAmount', fillTakerTokenAmount);
- await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper);
- const normalizedTakerAddress = takerAddress.toLowerCase();
- const zrxTokenAddress = this.getZRXTokenAddress();
- const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest);
- await this._orderValidationUtils.validateFillOrKillOrderThrowIfInvalidAsync(
- exchangeTradeEmulator,
- signedOrder,
- fillTakerTokenAmount,
- normalizedTakerAddress,
- zrxTokenAddress,
- );
- }
- /**
- * Checks if rounding error will be > 0.1% when computing makerTokenAmount by doing:
- * `(fillTakerTokenAmount * makerTokenAmount) / takerTokenAmount`.
- * 0x Protocol does not accept any trades that result in large rounding errors. This means that tokens with few or
- * no decimals can only be filled in quantities and ratios that avoid large rounding errors.
- * @param fillTakerTokenAmount The amount of the order (in taker tokens baseUnits) that you wish to fill.
- * @param takerTokenAmount The order size on the taker side
- * @param makerTokenAmount The order size on the maker side
- */
- public async isRoundingErrorAsync(
- fillTakerTokenAmount: BigNumber,
- takerTokenAmount: BigNumber,
- makerTokenAmount: BigNumber,
- ): Promise<boolean> {
- assert.isValidBaseUnitAmount('fillTakerTokenAmount', fillTakerTokenAmount);
- assert.isValidBaseUnitAmount('takerTokenAmount', takerTokenAmount);
- assert.isValidBaseUnitAmount('makerTokenAmount', makerTokenAmount);
- const exchangeInstance = await this._getExchangeContractAsync();
- const isRoundingError = await exchangeInstance.isRoundingError.callAsync(
- fillTakerTokenAmount,
- takerTokenAmount,
- makerTokenAmount,
- );
- return isRoundingError;
- }
- /**
- * Checks if logs contain LogError, which is emitted by Exchange contract on transaction failure.
- * @param logs Transaction logs as returned by `zeroEx.awaitTransactionMinedAsync`
- */
- public throwLogErrorsAsErrors(logs: Array<LogWithDecodedArgs<DecodedLogArgs> | LogEntry>): void {
- const errLog = _.find(logs, {
- event: ExchangeEvents.LogError,
- });
- if (!_.isUndefined(errLog)) {
- const logArgs = (errLog as LogWithDecodedArgs<LogErrorContractEventArgs>).args;
- const errCode = logArgs.errorId;
- const errMessage = this._exchangeContractErrCodesToMsg[errCode];
- throw new Error(errMessage);
- }
- }
- /**
- * Gets the latest OrderState of a signedOrder
- * @param signedOrder The signedOrder
- * @param stateLayer Optional, desired blockchain state layer (defaults to latest).
- * @return OrderState of the signedOrder
- */
- public async getOrderStateAsync(
- signedOrder: SignedOrder,
- stateLayer: BlockParamLiteral = BlockParamLiteral.Latest,
- ): Promise<OrderState> {
- const simpleBalanceAndProxyAllowanceFetcher = new SimpleBalanceAndProxyAllowanceFetcher(
- this._tokenWrapper,
- stateLayer,
- );
- const simpleOrderFilledCancelledFetcher = new SimpleOrderFilledCancelledFetcher(this, stateLayer);
- const orderStateUtils = new OrderStateUtils(
- simpleBalanceAndProxyAllowanceFetcher,
- simpleOrderFilledCancelledFetcher,
- );
- const orderState = orderStateUtils.getOrderStateAsync(signedOrder);
- return orderState;
- }
- /**
- * Returns the ZRX token address used by the exchange contract.
- * @return Address of ZRX token
- */
- public getZRXTokenAddress(): string {
- const contractAddress = this._getContractAddress(artifacts.ZRXArtifact, this._zrxContractAddressIfExists);
- return contractAddress;
- }
- private _invalidateContractInstances(): void {
- this.unsubscribeAll();
- delete this._exchangeContractIfExists;
- }
- private async _isValidSignatureUsingContractCallAsync(
- dataHex: string,
- ecSignature: ECSignature,
- signerAddressHex: string,
- ): Promise<boolean> {
- assert.isHexString('dataHex', dataHex);
- assert.doesConformToSchema('ecSignature', ecSignature, schemas.ecSignatureSchema);
- assert.isETHAddressHex('signerAddressHex', signerAddressHex);
- const normalizedSignerAddress = signerAddressHex.toLowerCase();
-
- const exchangeInstance = await this._getExchangeContractAsync();
-
- const isValidSignature = await exchangeInstance.isValidSignature.callAsync(
- normalizedSignerAddress,
- dataHex,
- ecSignature.v,
- ecSignature.r,
- ecSignature.s,
- );
- return isValidSignature;
- }
- private async _getOrderHashHexUsingContractCallAsync(order: Order | SignedOrder): Promise<string> {
- const exchangeInstance = await this._getExchangeContractAsync();
- const [orderAddresses, orderValues] = ExchangeWrapper._getOrderAddressesAndValues(order);
- const orderHashHex = await exchangeInstance.getOrderHash.callAsync(orderAddresses, orderValues);
- return orderHashHex;
- }
- private async _getExchangeContractAsync(): Promise<ExchangeContract> {
- if (!_.isUndefined(this._exchangeContractIfExists)) {
- return this._exchangeContractIfExists;
- }
- const [abi, address] = await this._getContractAbiAndAddressFromArtifactsAsync(
- artifacts.ExchangeArtifact,
- this._contractAddressIfExists,
- );
- const contractInstance = new ExchangeContract(
- abi,
- address,
- this._web3Wrapper.getProvider(),
- this._web3Wrapper.getContractDefaults(),
- );
- this._exchangeContractIfExists = contractInstance;
- return this._exchangeContractIfExists;
- }
- private async _getTokenTransferProxyAddressAsync(): Promise<string> {
- const exchangeInstance = await this._getExchangeContractAsync();
- const tokenTransferProxyAddress = await exchangeInstance.TOKEN_TRANSFER_PROXY_CONTRACT.callAsync();
- const tokenTransferProxyAddressLowerCase = tokenTransferProxyAddress.toLowerCase();
- return tokenTransferProxyAddressLowerCase;
- }
-} // tslint:disable:max-file-line-count
diff --git a/packages/0x.js/src/contract_wrappers/token_registry_wrapper.ts b/packages/0x.js/src/contract_wrappers/token_registry_wrapper.ts
deleted file mode 100644
index c4a193264..000000000
--- a/packages/0x.js/src/contract_wrappers/token_registry_wrapper.ts
+++ /dev/null
@@ -1,133 +0,0 @@
-import { Web3Wrapper } from '@0xproject/web3-wrapper';
-import * as _ from 'lodash';
-
-import { artifacts } from '../artifacts';
-import { Token, TokenMetadata } from '../types';
-import { assert } from '../utils/assert';
-import { constants } from '../utils/constants';
-
-import { ContractWrapper } from './contract_wrapper';
-import { TokenRegistryContract } from './generated/token_registry';
-
-/**
- * This class includes all the functionality related to interacting with the 0x Token Registry smart contract.
- */
-export class TokenRegistryWrapper extends ContractWrapper {
- private _tokenRegistryContractIfExists?: TokenRegistryContract;
- private _contractAddressIfExists?: string;
- private static _createTokenFromMetadata(metadata: TokenMetadata): Token | undefined {
- if (metadata[0] === constants.NULL_ADDRESS) {
- return undefined;
- }
- const token = {
- address: metadata[0],
- name: metadata[1],
- symbol: metadata[2],
- decimals: metadata[3],
- };
- return token;
- }
- constructor(web3Wrapper: Web3Wrapper, networkId: number, contractAddressIfExists?: string) {
- super(web3Wrapper, networkId);
- this._contractAddressIfExists = contractAddressIfExists;
- }
- /**
- * Retrieves all the tokens currently listed in the Token Registry smart contract
- * @return An array of objects that conform to the Token interface.
- */
- public async getTokensAsync(): Promise<Token[]> {
- const addresses = await this.getTokenAddressesAsync();
- const tokenPromises: Array<Promise<Token | undefined>> = _.map(addresses, async (address: string) =>
- this.getTokenIfExistsAsync(address),
- );
- const tokens = await Promise.all(tokenPromises);
- return tokens as Token[];
- }
- /**
- * Retrieves all the addresses of the tokens currently listed in the Token Registry smart contract
- * @return An array of token addresses.
- */
- public async getTokenAddressesAsync(): Promise<string[]> {
- const tokenRegistryContract = await this._getTokenRegistryContractAsync();
- const addresses = await tokenRegistryContract.getTokenAddresses.callAsync();
- const lowerCaseAddresses = _.map(addresses, address => address.toLowerCase());
- return lowerCaseAddresses;
- }
- /**
- * Retrieves a token by address currently listed in the Token Registry smart contract
- * @return An object that conforms to the Token interface or undefined if token not found.
- */
- public async getTokenIfExistsAsync(address: string): Promise<Token | undefined> {
- assert.isETHAddressHex('address', address);
- const normalizedAddress = address.toLowerCase();
-
- const tokenRegistryContract = await this._getTokenRegistryContractAsync();
- const metadata = await tokenRegistryContract.getTokenMetaData.callAsync(normalizedAddress);
- const token = TokenRegistryWrapper._createTokenFromMetadata(metadata);
- return token;
- }
- public async getTokenAddressBySymbolIfExistsAsync(symbol: string): Promise<string | undefined> {
- assert.isString('symbol', symbol);
- const tokenRegistryContract = await this._getTokenRegistryContractAsync();
- const addressIfExists = await tokenRegistryContract.getTokenAddressBySymbol.callAsync(symbol);
- if (addressIfExists === constants.NULL_ADDRESS) {
- return undefined;
- }
- return addressIfExists;
- }
- public async getTokenAddressByNameIfExistsAsync(name: string): Promise<string | undefined> {
- assert.isString('name', name);
- const tokenRegistryContract = await this._getTokenRegistryContractAsync();
- const addressIfExists = await tokenRegistryContract.getTokenAddressByName.callAsync(name);
- if (addressIfExists === constants.NULL_ADDRESS) {
- return undefined;
- }
- return addressIfExists;
- }
- public async getTokenBySymbolIfExistsAsync(symbol: string): Promise<Token | undefined> {
- assert.isString('symbol', symbol);
- const tokenRegistryContract = await this._getTokenRegistryContractAsync();
- const metadata = await tokenRegistryContract.getTokenBySymbol.callAsync(symbol);
- const token = TokenRegistryWrapper._createTokenFromMetadata(metadata);
- return token;
- }
- public async getTokenByNameIfExistsAsync(name: string): Promise<Token | undefined> {
- assert.isString('name', name);
- const tokenRegistryContract = await this._getTokenRegistryContractAsync();
- const metadata = await tokenRegistryContract.getTokenByName.callAsync(name);
- const token = TokenRegistryWrapper._createTokenFromMetadata(metadata);
- return token;
- }
- /**
- * Retrieves the Ethereum address of the TokenRegistry contract deployed on the network
- * that the user-passed web3 provider is connected to.
- * @returns The Ethereum address of the TokenRegistry contract being used.
- */
- public getContractAddress(): string {
- const contractAddress = this._getContractAddress(
- artifacts.TokenRegistryArtifact,
- this._contractAddressIfExists,
- );
- return contractAddress;
- }
- private _invalidateContractInstance(): void {
- delete this._tokenRegistryContractIfExists;
- }
- private async _getTokenRegistryContractAsync(): Promise<TokenRegistryContract> {
- if (!_.isUndefined(this._tokenRegistryContractIfExists)) {
- return this._tokenRegistryContractIfExists;
- }
- const [abi, address] = await this._getContractAbiAndAddressFromArtifactsAsync(
- artifacts.TokenRegistryArtifact,
- this._contractAddressIfExists,
- );
- const contractInstance = new TokenRegistryContract(
- abi,
- address,
- this._web3Wrapper.getProvider(),
- this._web3Wrapper.getContractDefaults(),
- );
- this._tokenRegistryContractIfExists = contractInstance;
- return this._tokenRegistryContractIfExists;
- }
-}
diff --git a/packages/0x.js/src/contract_wrappers/token_transfer_proxy_wrapper.ts b/packages/0x.js/src/contract_wrappers/token_transfer_proxy_wrapper.ts
deleted file mode 100644
index be558b5be..000000000
--- a/packages/0x.js/src/contract_wrappers/token_transfer_proxy_wrapper.ts
+++ /dev/null
@@ -1,75 +0,0 @@
-import { Web3Wrapper } from '@0xproject/web3-wrapper';
-import * as _ from 'lodash';
-
-import { artifacts } from '../artifacts';
-import { assert } from '../utils/assert';
-
-import { ContractWrapper } from './contract_wrapper';
-import { TokenTransferProxyContract } from './generated/token_transfer_proxy';
-
-/**
- * This class includes the functionality related to interacting with the TokenTransferProxy contract.
- */
-export class TokenTransferProxyWrapper extends ContractWrapper {
- private _tokenTransferProxyContractIfExists?: TokenTransferProxyContract;
- private _contractAddressIfExists?: string;
- constructor(web3Wrapper: Web3Wrapper, networkId: number, contractAddressIfExists?: string) {
- super(web3Wrapper, networkId);
- this._contractAddressIfExists = contractAddressIfExists;
- }
- /**
- * Check if the Exchange contract address is authorized by the TokenTransferProxy contract.
- * @param exchangeContractAddress The hex encoded address of the Exchange contract to call.
- * @return Whether the exchangeContractAddress is authorized.
- */
- public async isAuthorizedAsync(exchangeContractAddress: string): Promise<boolean> {
- assert.isETHAddressHex('exchangeContractAddress', exchangeContractAddress);
- const normalizedExchangeContractAddress = exchangeContractAddress.toLowerCase();
- const tokenTransferProxyContractInstance = await this._getTokenTransferProxyContractAsync();
- const isAuthorized = await tokenTransferProxyContractInstance.authorized.callAsync(
- normalizedExchangeContractAddress,
- );
- return isAuthorized;
- }
- /**
- * Get the list of all Exchange contract addresses authorized by the TokenTransferProxy contract.
- * @return The list of authorized addresses.
- */
- public async getAuthorizedAddressesAsync(): Promise<string[]> {
- const tokenTransferProxyContractInstance = await this._getTokenTransferProxyContractAsync();
- const authorizedAddresses = await tokenTransferProxyContractInstance.getAuthorizedAddresses.callAsync();
- return authorizedAddresses;
- }
- /**
- * Retrieves the Ethereum address of the TokenTransferProxy contract deployed on the network
- * that the user-passed web3 provider is connected to.
- * @returns The Ethereum address of the TokenTransferProxy contract being used.
- */
- public getContractAddress(): string {
- const contractAddress = this._getContractAddress(
- artifacts.TokenTransferProxyArtifact,
- this._contractAddressIfExists,
- );
- return contractAddress;
- }
- private _invalidateContractInstance(): void {
- delete this._tokenTransferProxyContractIfExists;
- }
- private async _getTokenTransferProxyContractAsync(): Promise<TokenTransferProxyContract> {
- if (!_.isUndefined(this._tokenTransferProxyContractIfExists)) {
- return this._tokenTransferProxyContractIfExists;
- }
- const [abi, address] = await this._getContractAbiAndAddressFromArtifactsAsync(
- artifacts.TokenTransferProxyArtifact,
- this._contractAddressIfExists,
- );
- const contractInstance = new TokenTransferProxyContract(
- abi,
- address,
- this._web3Wrapper.getProvider(),
- this._web3Wrapper.getContractDefaults(),
- );
- this._tokenTransferProxyContractIfExists = contractInstance;
- return this._tokenTransferProxyContractIfExists;
- }
-}
diff --git a/packages/0x.js/src/contract_wrappers/token_wrapper.ts b/packages/0x.js/src/contract_wrappers/token_wrapper.ts
deleted file mode 100644
index 194cfb5aa..000000000
--- a/packages/0x.js/src/contract_wrappers/token_wrapper.ts
+++ /dev/null
@@ -1,434 +0,0 @@
-import { schemas } from '@0xproject/json-schemas';
-import { LogWithDecodedArgs } from '@0xproject/types';
-import { AbiDecoder, BigNumber } from '@0xproject/utils';
-import { Web3Wrapper } from '@0xproject/web3-wrapper';
-import * as _ from 'lodash';
-
-import { artifacts } from '../artifacts';
-import { BlockRange, EventCallback, IndexedFilterValues, MethodOpts, TransactionOpts, ZeroExError } from '../types';
-import { assert } from '../utils/assert';
-import { constants } from '../utils/constants';
-
-import { ContractWrapper } from './contract_wrapper';
-import { TokenContract, TokenContractEventArgs, TokenEvents } from './generated/token';
-import { TokenTransferProxyWrapper } from './token_transfer_proxy_wrapper';
-
-/**
- * This class includes all the functionality related to interacting with ERC20 token contracts.
- * All ERC20 method calls are supported, along with some convenience methods for getting/setting allowances
- * to the 0x Proxy smart contract.
- */
-export class TokenWrapper extends ContractWrapper {
- public UNLIMITED_ALLOWANCE_IN_BASE_UNITS = constants.UNLIMITED_ALLOWANCE_IN_BASE_UNITS;
- private _tokenContractsByAddress: { [address: string]: TokenContract };
- private _tokenTransferProxyWrapper: TokenTransferProxyWrapper;
- constructor(web3Wrapper: Web3Wrapper, networkId: number, tokenTransferProxyWrapper: TokenTransferProxyWrapper) {
- super(web3Wrapper, networkId);
- this._tokenContractsByAddress = {};
- this._tokenTransferProxyWrapper = tokenTransferProxyWrapper;
- }
- /**
- * Retrieves an owner's ERC20 token balance.
- * @param tokenAddress The hex encoded contract Ethereum address where the ERC20 token is deployed.
- * @param ownerAddress The hex encoded user Ethereum address whose balance you would like to check.
- * @param methodOpts Optional arguments this method accepts.
- * @return The owner's ERC20 token balance in base units.
- */
- public async getBalanceAsync(
- tokenAddress: string,
- ownerAddress: string,
- methodOpts?: MethodOpts,
- ): Promise<BigNumber> {
- assert.isETHAddressHex('ownerAddress', ownerAddress);
- assert.isETHAddressHex('tokenAddress', tokenAddress);
- const normalizedTokenAddress = tokenAddress.toLowerCase();
- const normalizedOwnerAddress = ownerAddress.toLowerCase();
-
- const tokenContract = await this._getTokenContractAsync(normalizedTokenAddress);
- const defaultBlock = _.isUndefined(methodOpts) ? undefined : methodOpts.defaultBlock;
- const txData = {};
- let balance = await tokenContract.balanceOf.callAsync(normalizedOwnerAddress, txData, defaultBlock);
- // Wrap BigNumbers returned from web3 with our own (later) version of BigNumber
- balance = new BigNumber(balance);
- return balance;
- }
- /**
- * Sets the spender's allowance to a specified number of baseUnits on behalf of the owner address.
- * Equivalent to the ERC20 spec method `approve`.
- * @param tokenAddress The hex encoded contract Ethereum address where the ERC20 token is deployed.
- * @param ownerAddress The hex encoded user Ethereum address who would like to set an allowance
- * for spenderAddress.
- * @param spenderAddress The hex encoded user Ethereum address who will be able to spend the set allowance.
- * @param amountInBaseUnits The allowance amount you would like to set.
- * @param txOpts Transaction parameters.
- * @return Transaction hash.
- */
- public async setAllowanceAsync(
- tokenAddress: string,
- ownerAddress: string,
- spenderAddress: string,
- amountInBaseUnits: BigNumber,
- txOpts: TransactionOpts = {},
- ): Promise<string> {
- assert.isETHAddressHex('spenderAddress', spenderAddress);
- assert.isETHAddressHex('tokenAddress', tokenAddress);
- await assert.isSenderAddressAsync('ownerAddress', ownerAddress, this._web3Wrapper);
- const normalizedTokenAddress = tokenAddress.toLowerCase();
- const normalizedSpenderAddress = spenderAddress.toLowerCase();
- const normalizedOwnerAddress = ownerAddress.toLowerCase();
- assert.isValidBaseUnitAmount('amountInBaseUnits', amountInBaseUnits);
-
- const tokenContract = await this._getTokenContractAsync(normalizedTokenAddress);
- const txHash = await tokenContract.approve.sendTransactionAsync(normalizedSpenderAddress, amountInBaseUnits, {
- from: normalizedOwnerAddress,
- gas: txOpts.gasLimit,
- gasPrice: txOpts.gasPrice,
- });
- return txHash;
- }
- /**
- * Sets the spender's allowance to an unlimited number of baseUnits on behalf of the owner address.
- * Equivalent to the ERC20 spec method `approve`.
- * Setting an unlimited allowance will lower the gas cost for filling orders involving tokens that forego updating
- * allowances set to the max amount (e.g ZRX, WETH)
- * @param tokenAddress The hex encoded contract Ethereum address where the ERC20 token is deployed.
- * @param ownerAddress The hex encoded user Ethereum address who would like to set an allowance
- * for spenderAddress.
- * @param spenderAddress The hex encoded user Ethereum address who will be able to spend the set allowance.
- * @param txOpts Transaction parameters.
- * @return Transaction hash.
- */
- public async setUnlimitedAllowanceAsync(
- tokenAddress: string,
- ownerAddress: string,
- spenderAddress: string,
- txOpts: TransactionOpts = {},
- ): Promise<string> {
- assert.isETHAddressHex('ownerAddress', ownerAddress);
- assert.isETHAddressHex('tokenAddress', tokenAddress);
- assert.isETHAddressHex('spenderAddress', spenderAddress);
- const normalizedTokenAddress = tokenAddress.toLowerCase();
- const normalizedOwnerAddress = ownerAddress.toLowerCase();
- const normalizedSpenderAddress = spenderAddress.toLowerCase();
- const txHash = await this.setAllowanceAsync(
- normalizedTokenAddress,
- normalizedOwnerAddress,
- normalizedSpenderAddress,
- this.UNLIMITED_ALLOWANCE_IN_BASE_UNITS,
- txOpts,
- );
- return txHash;
- }
- /**
- * Retrieves the owners allowance in baseUnits set to the spender's address.
- * @param tokenAddress The hex encoded contract Ethereum address where the ERC20 token is deployed.
- * @param ownerAddress The hex encoded user Ethereum address whose allowance to spenderAddress
- * you would like to retrieve.
- * @param spenderAddress The hex encoded user Ethereum address who can spend the allowance you are fetching.
- * @param methodOpts Optional arguments this method accepts.
- */
- public async getAllowanceAsync(
- tokenAddress: string,
- ownerAddress: string,
- spenderAddress: string,
- methodOpts?: MethodOpts,
- ): Promise<BigNumber> {
- assert.isETHAddressHex('ownerAddress', ownerAddress);
- assert.isETHAddressHex('tokenAddress', tokenAddress);
- assert.isETHAddressHex('spenderAddress', spenderAddress);
- const normalizedTokenAddress = tokenAddress.toLowerCase();
- const normalizedOwnerAddress = ownerAddress.toLowerCase();
- const normalizedSpenderAddress = spenderAddress.toLowerCase();
-
- const tokenContract = await this._getTokenContractAsync(normalizedTokenAddress);
- const defaultBlock = _.isUndefined(methodOpts) ? undefined : methodOpts.defaultBlock;
- const txData = {};
- let allowanceInBaseUnits = await tokenContract.allowance.callAsync(
- normalizedOwnerAddress,
- normalizedSpenderAddress,
- txData,
- defaultBlock,
- );
- // Wrap BigNumbers returned from web3 with our own (later) version of BigNumber
- allowanceInBaseUnits = new BigNumber(allowanceInBaseUnits);
- return allowanceInBaseUnits;
- }
- /**
- * Retrieves the owner's allowance in baseUnits set to the 0x proxy contract.
- * @param tokenAddress The hex encoded contract Ethereum address where the ERC20 token is deployed.
- * @param ownerAddress The hex encoded user Ethereum address whose proxy contract allowance we are retrieving.
- * @param methodOpts Optional arguments this method accepts.
- */
- public async getProxyAllowanceAsync(
- tokenAddress: string,
- ownerAddress: string,
- methodOpts?: MethodOpts,
- ): Promise<BigNumber> {
- assert.isETHAddressHex('ownerAddress', ownerAddress);
- assert.isETHAddressHex('tokenAddress', tokenAddress);
- const normalizedTokenAddress = tokenAddress.toLowerCase();
- const normalizedOwnerAddress = ownerAddress.toLowerCase();
-
- const proxyAddress = this._tokenTransferProxyWrapper.getContractAddress();
- const allowanceInBaseUnits = await this.getAllowanceAsync(
- normalizedTokenAddress,
- normalizedOwnerAddress,
- proxyAddress,
- methodOpts,
- );
- return allowanceInBaseUnits;
- }
- /**
- * Sets the 0x proxy contract's allowance to a specified number of a tokens' baseUnits on behalf
- * of an owner address.
- * @param tokenAddress The hex encoded contract Ethereum address where the ERC20 token is deployed.
- * @param ownerAddress The hex encoded user Ethereum address who is setting an allowance
- * for the Proxy contract.
- * @param amountInBaseUnits The allowance amount specified in baseUnits.
- * @param txOpts Transaction parameters.
- * @return Transaction hash.
- */
- public async setProxyAllowanceAsync(
- tokenAddress: string,
- ownerAddress: string,
- amountInBaseUnits: BigNumber,
- txOpts: TransactionOpts = {},
- ): Promise<string> {
- assert.isETHAddressHex('ownerAddress', ownerAddress);
- assert.isETHAddressHex('tokenAddress', tokenAddress);
- const normalizedTokenAddress = tokenAddress.toLowerCase();
- const normalizedOwnerAddress = ownerAddress.toLowerCase();
- assert.isValidBaseUnitAmount('amountInBaseUnits', amountInBaseUnits);
-
- const proxyAddress = this._tokenTransferProxyWrapper.getContractAddress();
- const txHash = await this.setAllowanceAsync(
- normalizedTokenAddress,
- normalizedOwnerAddress,
- proxyAddress,
- amountInBaseUnits,
- txOpts,
- );
- return txHash;
- }
- /**
- * Sets the 0x proxy contract's allowance to a unlimited number of a tokens' baseUnits on behalf
- * of an owner address.
- * Setting an unlimited allowance will lower the gas cost for filling orders involving tokens that forego updating
- * allowances set to the max amount (e.g ZRX, WETH)
- * @param tokenAddress The hex encoded contract Ethereum address where the ERC20 token is deployed.
- * @param ownerAddress The hex encoded user Ethereum address who is setting an allowance
- * for the Proxy contract.
- * @param txOpts Transaction parameters.
- * @return Transaction hash.
- */
- public async setUnlimitedProxyAllowanceAsync(
- tokenAddress: string,
- ownerAddress: string,
- txOpts: TransactionOpts = {},
- ): Promise<string> {
- assert.isETHAddressHex('ownerAddress', ownerAddress);
- assert.isETHAddressHex('tokenAddress', tokenAddress);
- const normalizedTokenAddress = tokenAddress.toLowerCase();
- const normalizedOwnerAddress = ownerAddress.toLowerCase();
- const txHash = await this.setProxyAllowanceAsync(
- normalizedTokenAddress,
- normalizedOwnerAddress,
- this.UNLIMITED_ALLOWANCE_IN_BASE_UNITS,
- txOpts,
- );
- return txHash;
- }
- /**
- * Transfers `amountInBaseUnits` ERC20 tokens from `fromAddress` to `toAddress`.
- * @param tokenAddress The hex encoded contract Ethereum address where the ERC20 token is deployed.
- * @param fromAddress The hex encoded user Ethereum address that will send the funds.
- * @param toAddress The hex encoded user Ethereum address that will receive the funds.
- * @param amountInBaseUnits The amount (specified in baseUnits) of the token to transfer.
- * @param txOpts Transaction parameters.
- * @return Transaction hash.
- */
- public async transferAsync(
- tokenAddress: string,
- fromAddress: string,
- toAddress: string,
- amountInBaseUnits: BigNumber,
- txOpts: TransactionOpts = {},
- ): Promise<string> {
- assert.isETHAddressHex('tokenAddress', tokenAddress);
- assert.isETHAddressHex('toAddress', toAddress);
- await assert.isSenderAddressAsync('fromAddress', fromAddress, this._web3Wrapper);
- const normalizedTokenAddress = tokenAddress.toLowerCase();
- const normalizedFromAddress = fromAddress.toLowerCase();
- const normalizedToAddress = toAddress.toLowerCase();
- assert.isValidBaseUnitAmount('amountInBaseUnits', amountInBaseUnits);
-
- const tokenContract = await this._getTokenContractAsync(normalizedTokenAddress);
-
- const fromAddressBalance = await this.getBalanceAsync(normalizedTokenAddress, normalizedFromAddress);
- if (fromAddressBalance.lessThan(amountInBaseUnits)) {
- throw new Error(ZeroExError.InsufficientBalanceForTransfer);
- }
-
- const txHash = await tokenContract.transfer.sendTransactionAsync(normalizedToAddress, amountInBaseUnits, {
- from: normalizedFromAddress,
- gas: txOpts.gasLimit,
- gasPrice: txOpts.gasPrice,
- });
- return txHash;
- }
- /**
- * Transfers `amountInBaseUnits` ERC20 tokens from `fromAddress` to `toAddress`.
- * Requires the fromAddress to have sufficient funds and to have approved an allowance of
- * `amountInBaseUnits` to `senderAddress`.
- * @param tokenAddress The hex encoded contract Ethereum address where the ERC20 token is deployed.
- * @param fromAddress The hex encoded user Ethereum address whose funds are being sent.
- * @param toAddress The hex encoded user Ethereum address that will receive the funds.
- * @param senderAddress The hex encoded user Ethereum address whose initiates the fund transfer. The
- * `fromAddress` must have set an allowance to the `senderAddress`
- * before this call.
- * @param amountInBaseUnits The amount (specified in baseUnits) of the token to transfer.
- * @param txOpts Transaction parameters.
- * @return Transaction hash.
- */
- public async transferFromAsync(
- tokenAddress: string,
- fromAddress: string,
- toAddress: string,
- senderAddress: string,
- amountInBaseUnits: BigNumber,
- txOpts: TransactionOpts = {},
- ): Promise<string> {
- assert.isETHAddressHex('toAddress', toAddress);
- assert.isETHAddressHex('fromAddress', fromAddress);
- assert.isETHAddressHex('tokenAddress', tokenAddress);
- await assert.isSenderAddressAsync('senderAddress', senderAddress, this._web3Wrapper);
- const normalizedToAddress = toAddress.toLowerCase();
- const normalizedFromAddress = fromAddress.toLowerCase();
- const normalizedTokenAddress = tokenAddress.toLowerCase();
- const normalizedSenderAddress = senderAddress.toLowerCase();
- assert.isValidBaseUnitAmount('amountInBaseUnits', amountInBaseUnits);
-
- const tokenContract = await this._getTokenContractAsync(normalizedTokenAddress);
-
- const fromAddressAllowance = await this.getAllowanceAsync(
- normalizedTokenAddress,
- normalizedFromAddress,
- normalizedSenderAddress,
- );
- if (fromAddressAllowance.lessThan(amountInBaseUnits)) {
- throw new Error(ZeroExError.InsufficientAllowanceForTransfer);
- }
-
- const fromAddressBalance = await this.getBalanceAsync(normalizedTokenAddress, normalizedFromAddress);
- if (fromAddressBalance.lessThan(amountInBaseUnits)) {
- throw new Error(ZeroExError.InsufficientBalanceForTransfer);
- }
-
- const txHash = await tokenContract.transferFrom.sendTransactionAsync(
- normalizedFromAddress,
- normalizedToAddress,
- amountInBaseUnits,
- {
- from: normalizedSenderAddress,
- gas: txOpts.gasLimit,
- gasPrice: txOpts.gasPrice,
- },
- );
- return txHash;
- }
- /**
- * Subscribe to an event type emitted by the Token contract.
- * @param tokenAddress The hex encoded address where the ERC20 token is deployed.
- * @param eventName The token contract event you would like to subscribe to.
- * @param indexFilterValues An object where the keys are indexed args returned by the event and
- * the value is the value you are interested in. E.g `{maker: aUserAddressHex}`
- * @param callback Callback that gets called when a log is added/removed
- * @return Subscription token used later to unsubscribe
- */
- public subscribe<ArgsType extends TokenContractEventArgs>(
- tokenAddress: string,
- eventName: TokenEvents,
- indexFilterValues: IndexedFilterValues,
- callback: EventCallback<ArgsType>,
- ): string {
- assert.isETHAddressHex('tokenAddress', tokenAddress);
- const normalizedTokenAddress = tokenAddress.toLowerCase();
- assert.doesBelongToStringEnum('eventName', eventName, TokenEvents);
- assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema);
- assert.isFunction('callback', callback);
- const subscriptionToken = this._subscribe<ArgsType>(
- normalizedTokenAddress,
- eventName,
- indexFilterValues,
- artifacts.TokenArtifact.abi,
- callback,
- );
- return subscriptionToken;
- }
- /**
- * Cancel a subscription
- * @param subscriptionToken Subscription token returned by `subscribe()`
- */
- public unsubscribe(subscriptionToken: string): void {
- this._unsubscribe(subscriptionToken);
- }
- /**
- * Cancels all existing subscriptions
- */
- public unsubscribeAll(): void {
- super._unsubscribeAll();
- }
- /**
- * Gets historical logs without creating a subscription
- * @param tokenAddress An address of the token that emitted the logs.
- * @param eventName The token contract event you would like to subscribe to.
- * @param blockRange Block range to get logs from.
- * @param indexFilterValues An object where the keys are indexed args returned by the event and
- * the value is the value you are interested in. E.g `{_from: aUserAddressHex}`
- * @return Array of logs that match the parameters
- */
- public async getLogsAsync<ArgsType extends TokenContractEventArgs>(
- tokenAddress: string,
- eventName: TokenEvents,
- blockRange: BlockRange,
- indexFilterValues: IndexedFilterValues,
- ): Promise<Array<LogWithDecodedArgs<ArgsType>>> {
- assert.isETHAddressHex('tokenAddress', tokenAddress);
- const normalizedTokenAddress = tokenAddress.toLowerCase();
- assert.doesBelongToStringEnum('eventName', eventName, TokenEvents);
- assert.doesConformToSchema('blockRange', blockRange, schemas.blockRangeSchema);
- assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema);
- const logs = await this._getLogsAsync<ArgsType>(
- normalizedTokenAddress,
- eventName,
- blockRange,
- indexFilterValues,
- artifacts.TokenArtifact.abi,
- );
- return logs;
- }
- private _invalidateContractInstances(): void {
- this.unsubscribeAll();
- this._tokenContractsByAddress = {};
- }
- private async _getTokenContractAsync(tokenAddress: string): Promise<TokenContract> {
- const normalizedTokenAddress = tokenAddress.toLowerCase();
- let tokenContract = this._tokenContractsByAddress[normalizedTokenAddress];
- if (!_.isUndefined(tokenContract)) {
- return tokenContract;
- }
- const [abi, address] = await this._getContractAbiAndAddressFromArtifactsAsync(
- artifacts.TokenArtifact,
- normalizedTokenAddress,
- );
- const contractInstance = new TokenContract(
- abi,
- address,
- this._web3Wrapper.getProvider(),
- this._web3Wrapper.getContractDefaults(),
- );
- tokenContract = contractInstance;
- this._tokenContractsByAddress[normalizedTokenAddress] = tokenContract;
- return tokenContract;
- }
-}
diff --git a/packages/0x.js/src/fetchers/simple_balance_and_proxy_allowance_fetcher.ts b/packages/0x.js/src/fetchers/simple_balance_and_proxy_allowance_fetcher.ts
deleted file mode 100644
index 21774d794..000000000
--- a/packages/0x.js/src/fetchers/simple_balance_and_proxy_allowance_fetcher.ts
+++ /dev/null
@@ -1,28 +0,0 @@
-import { BlockParamLiteral } from '@0xproject/types';
-import { BigNumber } from '@0xproject/utils';
-
-import { BalanceAndProxyAllowanceFetcher } from '../abstract/balance_and_proxy_allowance_fetcher';
-import { TokenWrapper } from '../contract_wrappers/token_wrapper';
-
-export class SimpleBalanceAndProxyAllowanceFetcher implements BalanceAndProxyAllowanceFetcher {
- private _tokenWrapper: TokenWrapper;
- private _defaultBlock: BlockParamLiteral;
- constructor(token: TokenWrapper, defaultBlock: BlockParamLiteral) {
- this._tokenWrapper = token;
- this._defaultBlock = defaultBlock;
- }
- public async getBalanceAsync(tokenAddress: string, userAddress: string): Promise<BigNumber> {
- const methodOpts = {
- defaultBlock: this._defaultBlock,
- };
- const balance = this._tokenWrapper.getBalanceAsync(tokenAddress, userAddress, methodOpts);
- return balance;
- }
- public async getProxyAllowanceAsync(tokenAddress: string, userAddress: string): Promise<BigNumber> {
- const methodOpts = {
- defaultBlock: this._defaultBlock,
- };
- const proxyAllowance = this._tokenWrapper.getProxyAllowanceAsync(tokenAddress, userAddress, methodOpts);
- return proxyAllowance;
- }
-}
diff --git a/packages/0x.js/src/fetchers/simple_order_filled_cancelled_fetcher.ts b/packages/0x.js/src/fetchers/simple_order_filled_cancelled_fetcher.ts
deleted file mode 100644
index b7548d54d..000000000
--- a/packages/0x.js/src/fetchers/simple_order_filled_cancelled_fetcher.ts
+++ /dev/null
@@ -1,28 +0,0 @@
-import { BlockParamLiteral } from '@0xproject/types';
-import { BigNumber } from '@0xproject/utils';
-
-import { OrderFilledCancelledFetcher } from '../abstract/order_filled_cancelled_fetcher';
-import { ExchangeWrapper } from '../contract_wrappers/exchange_wrapper';
-
-export class SimpleOrderFilledCancelledFetcher implements OrderFilledCancelledFetcher {
- private _exchangeWrapper: ExchangeWrapper;
- private _defaultBlock: BlockParamLiteral;
- constructor(exchange: ExchangeWrapper, defaultBlock: BlockParamLiteral) {
- this._exchangeWrapper = exchange;
- this._defaultBlock = defaultBlock;
- }
- public async getFilledTakerAmountAsync(orderHash: string): Promise<BigNumber> {
- const methodOpts = {
- defaultBlock: this._defaultBlock,
- };
- const filledTakerAmount = this._exchangeWrapper.getFilledTakerAmountAsync(orderHash, methodOpts);
- return filledTakerAmount;
- }
- public async getCancelledTakerAmountAsync(orderHash: string): Promise<BigNumber> {
- const methodOpts = {
- defaultBlock: this._defaultBlock,
- };
- const cancelledTakerAmount = this._exchangeWrapper.getCancelledTakerAmountAsync(orderHash, methodOpts);
- return cancelledTakerAmount;
- }
-}
diff --git a/packages/0x.js/src/index.ts b/packages/0x.js/src/index.ts
index 3b973bd54..c79dbdb77 100644
--- a/packages/0x.js/src/index.ts
+++ b/packages/0x.js/src/index.ts
@@ -1,61 +1,51 @@
export { ZeroEx } from './0x';
export {
- ZeroExError,
- EventCallback,
- ExchangeContractErrs,
- ContractEvent,
- Token,
- IndexedFilterValues,
- BlockRange,
- OrderCancellationRequest,
- OrderFillRequest,
- ContractEventArgs,
- ZeroExConfig,
- MethodOpts,
- OrderTransactionOpts,
- TransactionOpts,
- LogEvent,
- DecodedLogEvent,
- EventWatcherCallback,
- OnOrderStateChangeCallback,
- OrderStateValid,
- OrderStateInvalid,
- OrderState,
-} from './types';
-
-export {
BlockParamLiteral,
FilterObject,
BlockParam,
ContractEventArg,
+ ExchangeContractErrs,
LogWithDecodedArgs,
Order,
Provider,
SignedOrder,
ECSignature,
+ OrderStateValid,
+ OrderStateInvalid,
+ OrderState,
+ Token,
TransactionReceipt,
TransactionReceiptWithDecodedLogs,
} from '@0xproject/types';
export {
+ EventCallback,
+ ContractEvent,
+ IndexedFilterValues,
+ BlockRange,
+ OrderCancellationRequest,
+ OrderFillRequest,
+ ContractEventArgs,
+ MethodOpts,
+ OrderTransactionOpts,
+ TransactionOpts,
+ LogEvent,
+ DecodedLogEvent,
+ OnOrderStateChangeCallback,
+ ContractWrappersError,
EtherTokenContractEventArgs,
WithdrawalContractEventArgs,
DepositContractEventArgs,
EtherTokenEvents,
-} from './contract_wrappers/generated/ether_token';
-
-export {
TransferContractEventArgs,
ApprovalContractEventArgs,
TokenContractEventArgs,
TokenEvents,
-} from './contract_wrappers/generated/token';
-
-export {
LogErrorContractEventArgs,
LogCancelContractEventArgs,
LogFillContractEventArgs,
ExchangeContractEventArgs,
ExchangeEvents,
-} from './contract_wrappers/generated/exchange';
+ ContractWrappersConfig,
+} from '@0xproject/contract-wrappers';
diff --git a/packages/0x.js/src/order_watcher/event_watcher.ts b/packages/0x.js/src/order_watcher/event_watcher.ts
deleted file mode 100644
index de5a99a46..000000000
--- a/packages/0x.js/src/order_watcher/event_watcher.ts
+++ /dev/null
@@ -1,99 +0,0 @@
-import { BlockParamLiteral, LogEntry } from '@0xproject/types';
-import { intervalUtils } from '@0xproject/utils';
-import { Web3Wrapper } from '@0xproject/web3-wrapper';
-import * as _ from 'lodash';
-
-import { EventWatcherCallback, ZeroExError } from '../types';
-import { assert } from '../utils/assert';
-
-const DEFAULT_EVENT_POLLING_INTERVAL_MS = 200;
-
-enum LogEventState {
- Removed,
- Added,
-}
-
-/**
- * The EventWatcher watches for blockchain events at the specified block confirmation
- * depth.
- */
-export class EventWatcher {
- private _web3Wrapper: Web3Wrapper;
- private _pollingIntervalMs: number;
- private _intervalIdIfExists?: NodeJS.Timer;
- private _lastEvents: LogEntry[] = [];
- private _stateLayer: BlockParamLiteral;
- constructor(
- web3Wrapper: Web3Wrapper,
- pollingIntervalIfExistsMs: undefined | number,
- stateLayer: BlockParamLiteral = BlockParamLiteral.Latest,
- ) {
- this._web3Wrapper = web3Wrapper;
- this._stateLayer = stateLayer;
- this._pollingIntervalMs = _.isUndefined(pollingIntervalIfExistsMs)
- ? DEFAULT_EVENT_POLLING_INTERVAL_MS
- : pollingIntervalIfExistsMs;
- }
- public subscribe(callback: EventWatcherCallback): void {
- assert.isFunction('callback', callback);
- if (!_.isUndefined(this._intervalIdIfExists)) {
- throw new Error(ZeroExError.SubscriptionAlreadyPresent);
- }
- this._intervalIdIfExists = intervalUtils.setAsyncExcludingInterval(
- this._pollForBlockchainEventsAsync.bind(this, callback),
- this._pollingIntervalMs,
- (err: Error) => {
- this.unsubscribe();
- callback(err);
- },
- );
- }
- public unsubscribe(): void {
- this._lastEvents = [];
- if (!_.isUndefined(this._intervalIdIfExists)) {
- intervalUtils.clearAsyncExcludingInterval(this._intervalIdIfExists);
- delete this._intervalIdIfExists;
- }
- }
- private async _pollForBlockchainEventsAsync(callback: EventWatcherCallback): Promise<void> {
- const pendingEvents = await this._getEventsAsync();
- if (_.isUndefined(pendingEvents)) {
- // HACK: This should never happen, but happens frequently on CI due to a ganache bug
- return;
- }
- if (pendingEvents.length === 0) {
- // HACK: Sometimes when node rebuilds the pending block we get back the empty result.
- // We don't want to emit a lot of removal events and bring them back after a couple of miliseconds,
- // that's why we just ignore those cases.
- return;
- }
- const removedEvents = _.differenceBy(this._lastEvents, pendingEvents, JSON.stringify);
- const newEvents = _.differenceBy(pendingEvents, this._lastEvents, JSON.stringify);
- await this._emitDifferencesAsync(removedEvents, LogEventState.Removed, callback);
- await this._emitDifferencesAsync(newEvents, LogEventState.Added, callback);
- this._lastEvents = pendingEvents;
- }
- private async _getEventsAsync(): Promise<LogEntry[]> {
- const eventFilter = {
- fromBlock: this._stateLayer,
- toBlock: this._stateLayer,
- };
- const events = await this._web3Wrapper.getLogsAsync(eventFilter);
- return events;
- }
- private async _emitDifferencesAsync(
- logs: LogEntry[],
- logEventState: LogEventState,
- callback: EventWatcherCallback,
- ): Promise<void> {
- for (const log of logs) {
- const logEvent = {
- removed: logEventState === LogEventState.Removed,
- ...log,
- };
- if (!_.isUndefined(this._intervalIdIfExists)) {
- callback(null, logEvent);
- }
- }
- }
-}
diff --git a/packages/0x.js/src/order_watcher/expiration_watcher.ts b/packages/0x.js/src/order_watcher/expiration_watcher.ts
deleted file mode 100644
index 27ec7107d..000000000
--- a/packages/0x.js/src/order_watcher/expiration_watcher.ts
+++ /dev/null
@@ -1,87 +0,0 @@
-import { BigNumber, intervalUtils } from '@0xproject/utils';
-import { RBTree } from 'bintrees';
-import * as _ from 'lodash';
-
-import { ZeroExError } from '../types';
-import { utils } from '../utils/utils';
-
-const DEFAULT_EXPIRATION_MARGIN_MS = 0;
-const DEFAULT_ORDER_EXPIRATION_CHECKING_INTERVAL_MS = 50;
-
-/**
- * This class includes the functionality to detect expired orders.
- * It stores them in a min heap by expiration time and checks for expired ones every `orderExpirationCheckingIntervalMs`
- */
-export class ExpirationWatcher {
- private _orderHashByExpirationRBTree: RBTree<string>;
- private _expiration: { [orderHash: string]: BigNumber } = {};
- private _orderExpirationCheckingIntervalMs: number;
- private _expirationMarginMs: number;
- private _orderExpirationCheckingIntervalIdIfExists?: NodeJS.Timer;
- constructor(expirationMarginIfExistsMs?: number, orderExpirationCheckingIntervalIfExistsMs?: number) {
- this._expirationMarginMs = expirationMarginIfExistsMs || DEFAULT_EXPIRATION_MARGIN_MS;
- this._orderExpirationCheckingIntervalMs =
- expirationMarginIfExistsMs || DEFAULT_ORDER_EXPIRATION_CHECKING_INTERVAL_MS;
- const comparator = (lhsOrderHash: string, rhsOrderHash: string) => {
- const lhsExpiration = this._expiration[lhsOrderHash].toNumber();
- const rhsExpiration = this._expiration[rhsOrderHash].toNumber();
- if (lhsExpiration !== rhsExpiration) {
- return lhsExpiration - rhsExpiration;
- } else {
- // HACK: If two orders have identical expirations, the order in which they are emitted by the
- // ExpirationWatcher does not matter, so we emit them in alphabetical order by orderHash.
- return lhsOrderHash.localeCompare(rhsOrderHash);
- }
- };
- this._orderHashByExpirationRBTree = new RBTree(comparator);
- }
- public subscribe(callback: (orderHash: string) => void): void {
- if (!_.isUndefined(this._orderExpirationCheckingIntervalIdIfExists)) {
- throw new Error(ZeroExError.SubscriptionAlreadyPresent);
- }
- this._orderExpirationCheckingIntervalIdIfExists = intervalUtils.setInterval(
- this._pruneExpiredOrders.bind(this, callback),
- this._orderExpirationCheckingIntervalMs,
- _.noop, // _pruneExpiredOrders never throws
- );
- }
- public unsubscribe(): void {
- if (_.isUndefined(this._orderExpirationCheckingIntervalIdIfExists)) {
- throw new Error(ZeroExError.SubscriptionNotFound);
- }
- intervalUtils.clearInterval(this._orderExpirationCheckingIntervalIdIfExists);
- delete this._orderExpirationCheckingIntervalIdIfExists;
- }
- public addOrder(orderHash: string, expirationUnixTimestampMs: BigNumber): void {
- this._expiration[orderHash] = expirationUnixTimestampMs;
- this._orderHashByExpirationRBTree.insert(orderHash);
- }
- public removeOrder(orderHash: string): void {
- if (_.isUndefined(this._expiration[orderHash])) {
- return; // noop since order already removed
- }
- this._orderHashByExpirationRBTree.remove(orderHash);
- delete this._expiration[orderHash];
- }
- private _pruneExpiredOrders(callback: (orderHash: string) => void): void {
- const currentUnixTimestampMs = utils.getCurrentUnixTimestampMs();
- while (true) {
- const hasTrakedOrders = this._orderHashByExpirationRBTree.size === 0;
- if (hasTrakedOrders) {
- break;
- }
- const nextOrderHashToExpire = this._orderHashByExpirationRBTree.min();
- const hasNoExpiredOrders = this._expiration[nextOrderHashToExpire].greaterThan(
- currentUnixTimestampMs.plus(this._expirationMarginMs),
- );
- const isSubscriptionActive = _.isUndefined(this._orderExpirationCheckingIntervalIdIfExists);
- if (hasNoExpiredOrders || isSubscriptionActive) {
- break;
- }
- const orderHash = this._orderHashByExpirationRBTree.min();
- this._orderHashByExpirationRBTree.remove(orderHash);
- delete this._expiration[orderHash];
- callback(orderHash);
- }
- }
-}
diff --git a/packages/0x.js/src/order_watcher/order_state_watcher.ts b/packages/0x.js/src/order_watcher/order_state_watcher.ts
deleted file mode 100644
index a9df8ac9d..000000000
--- a/packages/0x.js/src/order_watcher/order_state_watcher.ts
+++ /dev/null
@@ -1,381 +0,0 @@
-import { schemas } from '@0xproject/json-schemas';
-import { BlockParamLiteral, LogWithDecodedArgs, SignedOrder } from '@0xproject/types';
-import { AbiDecoder, intervalUtils } from '@0xproject/utils';
-import { Web3Wrapper } from '@0xproject/web3-wrapper';
-import * as _ from 'lodash';
-
-import { ZeroEx } from '../0x';
-import { ExchangeWrapper } from '../contract_wrappers/exchange_wrapper';
-import {
- DepositContractEventArgs,
- EtherTokenEvents,
- WithdrawalContractEventArgs,
-} from '../contract_wrappers/generated/ether_token';
-import {
- ExchangeEvents,
- LogCancelContractEventArgs,
- LogFillContractEventArgs,
-} from '../contract_wrappers/generated/exchange';
-import {
- ApprovalContractEventArgs,
- TokenEvents,
- TransferContractEventArgs,
-} from '../contract_wrappers/generated/token';
-import { TokenWrapper } from '../contract_wrappers/token_wrapper';
-import { BalanceAndProxyAllowanceLazyStore } from '../stores/balance_proxy_allowance_lazy_store';
-import { OrderFilledCancelledLazyStore } from '../stores/order_filled_cancelled_lazy_store';
-import {
- ContractEventArgs,
- ExchangeContractErrs,
- LogEvent,
- OnOrderStateChangeCallback,
- OrderState,
- OrderStateWatcherConfig,
- ZeroExError,
-} from '../types';
-import { assert } from '../utils/assert';
-import { OrderStateUtils } from '../utils/order_state_utils';
-import { utils } from '../utils/utils';
-
-import { EventWatcher } from './event_watcher';
-import { ExpirationWatcher } from './expiration_watcher';
-
-interface DependentOrderHashes {
- [makerAddress: string]: {
- [makerToken: string]: Set<string>;
- };
-}
-
-interface OrderByOrderHash {
- [orderHash: string]: SignedOrder;
-}
-
-interface OrderStateByOrderHash {
- [orderHash: string]: OrderState;
-}
-
-const DEFAULT_CLEANUP_JOB_INTERVAL_MS = 1000 * 60 * 60; // 1h
-
-/**
- * This class includes all the functionality related to watching a set of orders
- * for potential changes in order validity/fillability. The orderWatcher notifies
- * the subscriber of these changes so that a final decision can be made on whether
- * the order should be deemed invalid.
- */
-export class OrderStateWatcher {
- private _orderStateByOrderHashCache: OrderStateByOrderHash = {};
- private _orderByOrderHash: OrderByOrderHash = {};
- private _dependentOrderHashes: DependentOrderHashes = {};
- private _callbackIfExists?: OnOrderStateChangeCallback;
- private _eventWatcher: EventWatcher;
- private _web3Wrapper: Web3Wrapper;
- private _expirationWatcher: ExpirationWatcher;
- private _orderStateUtils: OrderStateUtils;
- private _orderFilledCancelledLazyStore: OrderFilledCancelledLazyStore;
- private _balanceAndProxyAllowanceLazyStore: BalanceAndProxyAllowanceLazyStore;
- private _cleanupJobInterval: number;
- private _cleanupJobIntervalIdIfExists?: NodeJS.Timer;
- constructor(
- web3Wrapper: Web3Wrapper,
- token: TokenWrapper,
- exchange: ExchangeWrapper,
- config?: OrderStateWatcherConfig,
- ) {
- this._web3Wrapper = web3Wrapper;
- const pollingIntervalIfExistsMs = _.isUndefined(config) ? undefined : config.eventPollingIntervalMs;
- const stateLayer =
- _.isUndefined(config) || _.isUndefined(config.stateLayer) ? BlockParamLiteral.Latest : config.stateLayer;
- this._eventWatcher = new EventWatcher(web3Wrapper, pollingIntervalIfExistsMs, stateLayer);
- this._balanceAndProxyAllowanceLazyStore = new BalanceAndProxyAllowanceLazyStore(token, stateLayer);
- this._orderFilledCancelledLazyStore = new OrderFilledCancelledLazyStore(exchange, stateLayer);
- this._orderStateUtils = new OrderStateUtils(
- this._balanceAndProxyAllowanceLazyStore,
- this._orderFilledCancelledLazyStore,
- );
- const orderExpirationCheckingIntervalMsIfExists = _.isUndefined(config)
- ? undefined
- : config.orderExpirationCheckingIntervalMs;
- const expirationMarginIfExistsMs = _.isUndefined(config) ? undefined : config.expirationMarginMs;
- this._expirationWatcher = new ExpirationWatcher(
- expirationMarginIfExistsMs,
- orderExpirationCheckingIntervalMsIfExists,
- );
- this._cleanupJobInterval =
- _.isUndefined(config) || _.isUndefined(config.cleanupJobIntervalMs)
- ? DEFAULT_CLEANUP_JOB_INTERVAL_MS
- : config.cleanupJobIntervalMs;
- }
- /**
- * Add an order to the orderStateWatcher. Before the order is added, it's
- * signature is verified.
- * @param signedOrder The order you wish to start watching.
- */
- public addOrder(signedOrder: SignedOrder): void {
- assert.doesConformToSchema('signedOrder', signedOrder, schemas.signedOrderSchema);
- const orderHash = ZeroEx.getOrderHashHex(signedOrder);
- assert.isValidSignature(orderHash, signedOrder.ecSignature, signedOrder.maker);
- this._orderByOrderHash[orderHash] = signedOrder;
- this._addToDependentOrderHashes(signedOrder, orderHash);
- const expirationUnixTimestampMs = signedOrder.expirationUnixTimestampSec.times(1000);
- this._expirationWatcher.addOrder(orderHash, expirationUnixTimestampMs);
- }
- /**
- * Removes an order from the orderStateWatcher
- * @param orderHash The orderHash of the order you wish to stop watching.
- */
- public removeOrder(orderHash: string): void {
- assert.doesConformToSchema('orderHash', orderHash, schemas.orderHashSchema);
- const signedOrder = this._orderByOrderHash[orderHash];
- if (_.isUndefined(signedOrder)) {
- return; // noop
- }
- delete this._orderByOrderHash[orderHash];
- delete this._orderStateByOrderHashCache[orderHash];
- const exchange = (this._orderFilledCancelledLazyStore as any)._exchangeWrapper as ExchangeWrapper;
- const zrxTokenAddress = exchange.getZRXTokenAddress();
-
- this._removeFromDependentOrderHashes(signedOrder.maker, zrxTokenAddress, orderHash);
- if (zrxTokenAddress !== signedOrder.makerTokenAddress) {
- this._removeFromDependentOrderHashes(signedOrder.maker, signedOrder.makerTokenAddress, orderHash);
- }
-
- this._expirationWatcher.removeOrder(orderHash);
- }
- /**
- * Starts an orderStateWatcher subscription. The callback will be called every time a watched order's
- * backing blockchain state has changed. This is a call-to-action for the caller to re-validate the order.
- * @param callback Receives the orderHash of the order that should be re-validated, together
- * with all the order-relevant blockchain state needed to re-validate the order.
- */
- public subscribe(callback: OnOrderStateChangeCallback): void {
- assert.isFunction('callback', callback);
- if (!_.isUndefined(this._callbackIfExists)) {
- throw new Error(ZeroExError.SubscriptionAlreadyPresent);
- }
- this._callbackIfExists = callback;
- this._eventWatcher.subscribe(this._onEventWatcherCallbackAsync.bind(this));
- this._expirationWatcher.subscribe(this._onOrderExpired.bind(this));
- this._cleanupJobIntervalIdIfExists = intervalUtils.setAsyncExcludingInterval(
- this._cleanupAsync.bind(this),
- this._cleanupJobInterval,
- (err: Error) => {
- this.unsubscribe();
- callback(err);
- },
- );
- }
- /**
- * Ends an orderStateWatcher subscription.
- */
- public unsubscribe(): void {
- if (_.isUndefined(this._callbackIfExists) || _.isUndefined(this._cleanupJobIntervalIdIfExists)) {
- throw new Error(ZeroExError.SubscriptionNotFound);
- }
- this._balanceAndProxyAllowanceLazyStore.deleteAll();
- this._orderFilledCancelledLazyStore.deleteAll();
- delete this._callbackIfExists;
- this._eventWatcher.unsubscribe();
- this._expirationWatcher.unsubscribe();
- intervalUtils.clearAsyncExcludingInterval(this._cleanupJobIntervalIdIfExists);
- }
- private async _cleanupAsync(): Promise<void> {
- for (const orderHash of _.keys(this._orderByOrderHash)) {
- this._cleanupOrderRelatedState(orderHash);
- await this._emitRevalidateOrdersAsync([orderHash]);
- }
- }
- private _cleanupOrderRelatedState(orderHash: string): void {
- const signedOrder = this._orderByOrderHash[orderHash];
-
- this._orderFilledCancelledLazyStore.deleteFilledTakerAmount(orderHash);
- this._orderFilledCancelledLazyStore.deleteCancelledTakerAmount(orderHash);
-
- this._balanceAndProxyAllowanceLazyStore.deleteBalance(signedOrder.makerTokenAddress, signedOrder.maker);
- this._balanceAndProxyAllowanceLazyStore.deleteProxyAllowance(signedOrder.makerTokenAddress, signedOrder.maker);
- this._balanceAndProxyAllowanceLazyStore.deleteBalance(signedOrder.takerTokenAddress, signedOrder.taker);
- this._balanceAndProxyAllowanceLazyStore.deleteProxyAllowance(signedOrder.takerTokenAddress, signedOrder.taker);
-
- const zrxTokenAddress = this._getZRXTokenAddress();
- if (!signedOrder.makerFee.isZero()) {
- this._balanceAndProxyAllowanceLazyStore.deleteBalance(zrxTokenAddress, signedOrder.maker);
- this._balanceAndProxyAllowanceLazyStore.deleteProxyAllowance(zrxTokenAddress, signedOrder.maker);
- }
- if (!signedOrder.takerFee.isZero()) {
- this._balanceAndProxyAllowanceLazyStore.deleteBalance(zrxTokenAddress, signedOrder.taker);
- this._balanceAndProxyAllowanceLazyStore.deleteProxyAllowance(zrxTokenAddress, signedOrder.taker);
- }
- }
- private _onOrderExpired(orderHash: string): void {
- const orderState: OrderState = {
- isValid: false,
- orderHash,
- error: ExchangeContractErrs.OrderFillExpired,
- };
- if (!_.isUndefined(this._orderByOrderHash[orderHash])) {
- this.removeOrder(orderHash);
- if (!_.isUndefined(this._callbackIfExists)) {
- this._callbackIfExists(null, orderState);
- }
- }
- }
- private async _onEventWatcherCallbackAsync(err: Error | null, logIfExists?: LogEvent): Promise<void> {
- if (!_.isNull(err)) {
- if (!_.isUndefined(this._callbackIfExists)) {
- this._callbackIfExists(err);
- this.unsubscribe();
- }
- return;
- }
- const log = logIfExists as LogEvent; // At this moment we are sure that no error occured and log is defined.
- const maybeDecodedLog = this._web3Wrapper.abiDecoder.tryToDecodeLogOrNoop<ContractEventArgs>(log);
- const isLogDecoded = !_.isUndefined(((maybeDecodedLog as any) as LogWithDecodedArgs<ContractEventArgs>).event);
- if (!isLogDecoded) {
- return; // noop
- }
- const decodedLog = (maybeDecodedLog as any) as LogWithDecodedArgs<ContractEventArgs>;
- let makerToken: string;
- let makerAddress: string;
- switch (decodedLog.event) {
- case TokenEvents.Approval: {
- // Invalidate cache
- const args = decodedLog.args as ApprovalContractEventArgs;
- this._balanceAndProxyAllowanceLazyStore.deleteProxyAllowance(decodedLog.address, args._owner);
- // Revalidate orders
- makerToken = decodedLog.address;
- makerAddress = args._owner;
- if (
- !_.isUndefined(this._dependentOrderHashes[makerAddress]) &&
- !_.isUndefined(this._dependentOrderHashes[makerAddress][makerToken])
- ) {
- const orderHashes = Array.from(this._dependentOrderHashes[makerAddress][makerToken]);
- await this._emitRevalidateOrdersAsync(orderHashes);
- }
- break;
- }
- case TokenEvents.Transfer: {
- // Invalidate cache
- const args = decodedLog.args as TransferContractEventArgs;
- this._balanceAndProxyAllowanceLazyStore.deleteBalance(decodedLog.address, args._from);
- this._balanceAndProxyAllowanceLazyStore.deleteBalance(decodedLog.address, args._to);
- // Revalidate orders
- makerToken = decodedLog.address;
- makerAddress = args._from;
- if (
- !_.isUndefined(this._dependentOrderHashes[makerAddress]) &&
- !_.isUndefined(this._dependentOrderHashes[makerAddress][makerToken])
- ) {
- const orderHashes = Array.from(this._dependentOrderHashes[makerAddress][makerToken]);
- await this._emitRevalidateOrdersAsync(orderHashes);
- }
- break;
- }
- case EtherTokenEvents.Deposit: {
- // Invalidate cache
- const args = decodedLog.args as DepositContractEventArgs;
- this._balanceAndProxyAllowanceLazyStore.deleteBalance(decodedLog.address, args._owner);
- // Revalidate orders
- makerToken = decodedLog.address;
- makerAddress = args._owner;
- if (
- !_.isUndefined(this._dependentOrderHashes[makerAddress]) &&
- !_.isUndefined(this._dependentOrderHashes[makerAddress][makerToken])
- ) {
- const orderHashes = Array.from(this._dependentOrderHashes[makerAddress][makerToken]);
- await this._emitRevalidateOrdersAsync(orderHashes);
- }
- break;
- }
- case EtherTokenEvents.Withdrawal: {
- // Invalidate cache
- const args = decodedLog.args as WithdrawalContractEventArgs;
- this._balanceAndProxyAllowanceLazyStore.deleteBalance(decodedLog.address, args._owner);
- // Revalidate orders
- makerToken = decodedLog.address;
- makerAddress = args._owner;
- if (
- !_.isUndefined(this._dependentOrderHashes[makerAddress]) &&
- !_.isUndefined(this._dependentOrderHashes[makerAddress][makerToken])
- ) {
- const orderHashes = Array.from(this._dependentOrderHashes[makerAddress][makerToken]);
- await this._emitRevalidateOrdersAsync(orderHashes);
- }
- break;
- }
- case ExchangeEvents.LogFill: {
- // Invalidate cache
- const args = decodedLog.args as LogFillContractEventArgs;
- this._orderFilledCancelledLazyStore.deleteFilledTakerAmount(args.orderHash);
- // Revalidate orders
- const orderHash = args.orderHash;
- const isOrderWatched = !_.isUndefined(this._orderByOrderHash[orderHash]);
- if (isOrderWatched) {
- await this._emitRevalidateOrdersAsync([orderHash]);
- }
- break;
- }
- case ExchangeEvents.LogCancel: {
- // Invalidate cache
- const args = decodedLog.args as LogCancelContractEventArgs;
- this._orderFilledCancelledLazyStore.deleteCancelledTakerAmount(args.orderHash);
- // Revalidate orders
- const orderHash = args.orderHash;
- const isOrderWatched = !_.isUndefined(this._orderByOrderHash[orderHash]);
- if (isOrderWatched) {
- await this._emitRevalidateOrdersAsync([orderHash]);
- }
- break;
- }
- case ExchangeEvents.LogError:
- return; // noop
-
- default:
- throw utils.spawnSwitchErr('decodedLog.event', decodedLog.event);
- }
- }
- private async _emitRevalidateOrdersAsync(orderHashes: string[]): Promise<void> {
- for (const orderHash of orderHashes) {
- const signedOrder = this._orderByOrderHash[orderHash];
- // Most of these calls will never reach the network because the data is fetched from stores
- // and only updated when cache is invalidated
- const orderState = await this._orderStateUtils.getOrderStateAsync(signedOrder);
- if (_.isUndefined(this._callbackIfExists)) {
- break; // Unsubscribe was called
- }
- if (_.isEqual(orderState, this._orderStateByOrderHashCache[orderHash])) {
- // Actual order state didn't change
- continue;
- } else {
- this._orderStateByOrderHashCache[orderHash] = orderState;
- }
- this._callbackIfExists(null, orderState);
- }
- }
- private _addToDependentOrderHashes(signedOrder: SignedOrder, orderHash: string): void {
- if (_.isUndefined(this._dependentOrderHashes[signedOrder.maker])) {
- this._dependentOrderHashes[signedOrder.maker] = {};
- }
- if (_.isUndefined(this._dependentOrderHashes[signedOrder.maker][signedOrder.makerTokenAddress])) {
- this._dependentOrderHashes[signedOrder.maker][signedOrder.makerTokenAddress] = new Set();
- }
- this._dependentOrderHashes[signedOrder.maker][signedOrder.makerTokenAddress].add(orderHash);
- const zrxTokenAddress = this._getZRXTokenAddress();
- if (_.isUndefined(this._dependentOrderHashes[signedOrder.maker][zrxTokenAddress])) {
- this._dependentOrderHashes[signedOrder.maker][zrxTokenAddress] = new Set();
- }
- this._dependentOrderHashes[signedOrder.maker][zrxTokenAddress].add(orderHash);
- }
- private _removeFromDependentOrderHashes(makerAddress: string, tokenAddress: string, orderHash: string) {
- this._dependentOrderHashes[makerAddress][tokenAddress].delete(orderHash);
- if (this._dependentOrderHashes[makerAddress][tokenAddress].size === 0) {
- delete this._dependentOrderHashes[makerAddress][tokenAddress];
- }
- if (_.isEmpty(this._dependentOrderHashes[makerAddress])) {
- delete this._dependentOrderHashes[makerAddress];
- }
- }
- private _getZRXTokenAddress(): string {
- const exchange = (this._orderFilledCancelledLazyStore as any)._exchangeWrapper as ExchangeWrapper;
- const zrxTokenAddress = exchange.getZRXTokenAddress();
- return zrxTokenAddress;
- }
-}
diff --git a/packages/0x.js/src/order_watcher/remaining_fillable_calculator.ts b/packages/0x.js/src/order_watcher/remaining_fillable_calculator.ts
deleted file mode 100644
index 184c13aa4..000000000
--- a/packages/0x.js/src/order_watcher/remaining_fillable_calculator.ts
+++ /dev/null
@@ -1,95 +0,0 @@
-import { SignedOrder } from '@0xproject/types';
-import { BigNumber } from '@0xproject/utils';
-
-export class RemainingFillableCalculator {
- private _signedOrder: SignedOrder;
- private _isMakerTokenZRX: boolean;
- // Transferrable Amount is the minimum of Approval and Balance
- private _transferrableMakerTokenAmount: BigNumber;
- private _transferrableMakerFeeTokenAmount: BigNumber;
- private _remainingMakerTokenAmount: BigNumber;
- private _remainingMakerFeeAmount: BigNumber;
- constructor(
- signedOrder: SignedOrder,
- isMakerTokenZRX: boolean,
- transferrableMakerTokenAmount: BigNumber,
- transferrableMakerFeeTokenAmount: BigNumber,
- remainingMakerTokenAmount: BigNumber,
- ) {
- this._signedOrder = signedOrder;
- this._isMakerTokenZRX = isMakerTokenZRX;
- this._transferrableMakerTokenAmount = transferrableMakerTokenAmount;
- this._transferrableMakerFeeTokenAmount = transferrableMakerFeeTokenAmount;
- this._remainingMakerTokenAmount = remainingMakerTokenAmount;
- this._remainingMakerFeeAmount = remainingMakerTokenAmount
- .times(signedOrder.makerFee)
- .dividedToIntegerBy(signedOrder.makerTokenAmount);
- }
- public computeRemainingMakerFillable(): BigNumber {
- if (this._hasSufficientFundsForFeeAndTransferAmount()) {
- return this._remainingMakerTokenAmount;
- }
- if (this._signedOrder.makerFee.isZero()) {
- return BigNumber.min(this._remainingMakerTokenAmount, this._transferrableMakerTokenAmount);
- }
- return this._calculatePartiallyFillableMakerTokenAmount();
- }
- public computeRemainingTakerFillable(): BigNumber {
- return this.computeRemainingMakerFillable()
- .times(this._signedOrder.takerTokenAmount)
- .dividedToIntegerBy(this._signedOrder.makerTokenAmount);
- }
- private _hasSufficientFundsForFeeAndTransferAmount(): boolean {
- if (this._isMakerTokenZRX) {
- const totalZRXTransferAmountRequired = this._remainingMakerTokenAmount.plus(this._remainingMakerFeeAmount);
- const hasSufficientFunds = this._transferrableMakerTokenAmount.greaterThanOrEqualTo(
- totalZRXTransferAmountRequired,
- );
- return hasSufficientFunds;
- } else {
- const hasSufficientFundsForTransferAmount = this._transferrableMakerTokenAmount.greaterThanOrEqualTo(
- this._remainingMakerTokenAmount,
- );
- const hasSufficientFundsForFeeAmount = this._transferrableMakerFeeTokenAmount.greaterThanOrEqualTo(
- this._remainingMakerFeeAmount,
- );
- const hasSufficientFunds = hasSufficientFundsForTransferAmount && hasSufficientFundsForFeeAmount;
- return hasSufficientFunds;
- }
- }
- private _calculatePartiallyFillableMakerTokenAmount(): BigNumber {
- // Given an order for 200 wei for 2 ZRXwei fee, find 100 wei for 1 ZRXwei. Order ratio is then 100:1
- const orderToFeeRatio = this._signedOrder.makerTokenAmount.dividedBy(this._signedOrder.makerFee);
- // The number of times the maker can fill the order, if each fill only required the transfer of a single
- // baseUnit of fee tokens.
- // 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,
- this._remainingMakerFeeAmount,
- );
- // 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.
- let fillableTimesInMakerTokenUnits = this._transferrableMakerTokenAmount.dividedBy(orderToFeeRatio);
- if (this._isMakerTokenZRX) {
- // If ZRX is the maker token, the Fee and the Maker amount need to be removed from the same pool;
- // 200 ZRXwei for 2ZRXwei fee can only be filled once (need 202 ZRXwei)
- const totalZRXTokenPooled = this._transferrableMakerTokenAmount;
- // 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
- fillableTimesInMakerTokenUnits = totalZRXTokenPooled.dividedBy(orderToFeeRatio.plus(new BigNumber(1)));
- }
- // 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.
- const partiallyFillableMakerTokenAmount = fillableTimesInMakerTokenUnits
- .times(this._signedOrder.makerTokenAmount)
- .dividedToIntegerBy(this._signedOrder.makerFee);
- const partiallyFillableFeeTokenAmount = fillableTimesInFeeTokenBaseUnits
- .times(this._signedOrder.makerTokenAmount)
- .dividedToIntegerBy(this._signedOrder.makerFee);
- const partiallyFillableAmount = BigNumber.min(
- partiallyFillableMakerTokenAmount,
- partiallyFillableFeeTokenAmount,
- );
- return partiallyFillableAmount;
- }
-}
diff --git a/packages/0x.js/src/stores/balance_proxy_allowance_lazy_store.ts b/packages/0x.js/src/stores/balance_proxy_allowance_lazy_store.ts
deleted file mode 100644
index 3ff116db4..000000000
--- a/packages/0x.js/src/stores/balance_proxy_allowance_lazy_store.ts
+++ /dev/null
@@ -1,91 +0,0 @@
-import { BlockParamLiteral } from '@0xproject/types';
-import { BigNumber } from '@0xproject/utils';
-import * as _ from 'lodash';
-
-import { BalanceAndProxyAllowanceFetcher } from '../abstract/balance_and_proxy_allowance_fetcher';
-import { TokenWrapper } from '../contract_wrappers/token_wrapper';
-
-/**
- * Copy on read store for balances/proxyAllowances of tokens/accounts
- */
-export class BalanceAndProxyAllowanceLazyStore implements BalanceAndProxyAllowanceFetcher {
- private _tokenWrapper: TokenWrapper;
- private _defaultBlock: BlockParamLiteral;
- private _balance: {
- [tokenAddress: string]: {
- [userAddress: string]: BigNumber;
- };
- };
- private _proxyAllowance: {
- [tokenAddress: string]: {
- [userAddress: string]: BigNumber;
- };
- };
- constructor(token: TokenWrapper, defaultBlock: BlockParamLiteral) {
- this._tokenWrapper = token;
- this._defaultBlock = defaultBlock;
- this._balance = {};
- this._proxyAllowance = {};
- }
- public async getBalanceAsync(tokenAddress: string, userAddress: string): Promise<BigNumber> {
- if (_.isUndefined(this._balance[tokenAddress]) || _.isUndefined(this._balance[tokenAddress][userAddress])) {
- const methodOpts = {
- defaultBlock: this._defaultBlock,
- };
- const balance = await this._tokenWrapper.getBalanceAsync(tokenAddress, userAddress, methodOpts);
- this.setBalance(tokenAddress, userAddress, balance);
- }
- const cachedBalance = this._balance[tokenAddress][userAddress];
- return cachedBalance;
- }
- public setBalance(tokenAddress: string, userAddress: string, balance: BigNumber): void {
- if (_.isUndefined(this._balance[tokenAddress])) {
- this._balance[tokenAddress] = {};
- }
- this._balance[tokenAddress][userAddress] = balance;
- }
- public deleteBalance(tokenAddress: string, userAddress: string): void {
- if (!_.isUndefined(this._balance[tokenAddress])) {
- delete this._balance[tokenAddress][userAddress];
- if (_.isEmpty(this._balance[tokenAddress])) {
- delete this._balance[tokenAddress];
- }
- }
- }
- public async getProxyAllowanceAsync(tokenAddress: string, userAddress: string): Promise<BigNumber> {
- if (
- _.isUndefined(this._proxyAllowance[tokenAddress]) ||
- _.isUndefined(this._proxyAllowance[tokenAddress][userAddress])
- ) {
- const methodOpts = {
- defaultBlock: this._defaultBlock,
- };
- const proxyAllowance = await this._tokenWrapper.getProxyAllowanceAsync(
- tokenAddress,
- userAddress,
- methodOpts,
- );
- this.setProxyAllowance(tokenAddress, userAddress, proxyAllowance);
- }
- const cachedProxyAllowance = this._proxyAllowance[tokenAddress][userAddress];
- return cachedProxyAllowance;
- }
- public setProxyAllowance(tokenAddress: string, userAddress: string, proxyAllowance: BigNumber): void {
- if (_.isUndefined(this._proxyAllowance[tokenAddress])) {
- this._proxyAllowance[tokenAddress] = {};
- }
- this._proxyAllowance[tokenAddress][userAddress] = proxyAllowance;
- }
- public deleteProxyAllowance(tokenAddress: string, userAddress: string): void {
- if (!_.isUndefined(this._proxyAllowance[tokenAddress])) {
- delete this._proxyAllowance[tokenAddress][userAddress];
- if (_.isEmpty(this._proxyAllowance[tokenAddress])) {
- delete this._proxyAllowance[tokenAddress];
- }
- }
- }
- public deleteAll(): void {
- this._balance = {};
- this._proxyAllowance = {};
- }
-}
diff --git a/packages/0x.js/src/stores/order_filled_cancelled_lazy_store.ts b/packages/0x.js/src/stores/order_filled_cancelled_lazy_store.ts
deleted file mode 100644
index 61d2db8c2..000000000
--- a/packages/0x.js/src/stores/order_filled_cancelled_lazy_store.ts
+++ /dev/null
@@ -1,67 +0,0 @@
-import { BlockParamLiteral } from '@0xproject/types';
-import { BigNumber } from '@0xproject/utils';
-import * as _ from 'lodash';
-
-import { OrderFilledCancelledFetcher } from '../abstract/order_filled_cancelled_fetcher';
-import { ExchangeWrapper } from '../contract_wrappers/exchange_wrapper';
-
-/**
- * Copy on read store for filled/cancelled taker amounts
- */
-export class OrderFilledCancelledLazyStore implements OrderFilledCancelledFetcher {
- private _exchangeWrapper: ExchangeWrapper;
- private _defaultBlock: BlockParamLiteral;
- private _filledTakerAmount: {
- [orderHash: string]: BigNumber;
- };
- private _cancelledTakerAmount: {
- [orderHash: string]: BigNumber;
- };
- constructor(exchange: ExchangeWrapper, defaultBlock: BlockParamLiteral) {
- this._exchangeWrapper = exchange;
- this._defaultBlock = defaultBlock;
- this._filledTakerAmount = {};
- this._cancelledTakerAmount = {};
- }
- public async getFilledTakerAmountAsync(orderHash: string): Promise<BigNumber> {
- if (_.isUndefined(this._filledTakerAmount[orderHash])) {
- const methodOpts = {
- defaultBlock: this._defaultBlock,
- };
- const filledTakerAmount = await this._exchangeWrapper.getFilledTakerAmountAsync(orderHash, methodOpts);
- this.setFilledTakerAmount(orderHash, filledTakerAmount);
- }
- const cachedFilled = this._filledTakerAmount[orderHash];
- return cachedFilled;
- }
- public setFilledTakerAmount(orderHash: string, filledTakerAmount: BigNumber): void {
- this._filledTakerAmount[orderHash] = filledTakerAmount;
- }
- public deleteFilledTakerAmount(orderHash: string): void {
- delete this._filledTakerAmount[orderHash];
- }
- public async getCancelledTakerAmountAsync(orderHash: string): Promise<BigNumber> {
- if (_.isUndefined(this._cancelledTakerAmount[orderHash])) {
- const methodOpts = {
- defaultBlock: this._defaultBlock,
- };
- const cancelledTakerAmount = await this._exchangeWrapper.getCancelledTakerAmountAsync(
- orderHash,
- methodOpts,
- );
- this.setCancelledTakerAmount(orderHash, cancelledTakerAmount);
- }
- const cachedCancelled = this._cancelledTakerAmount[orderHash];
- return cachedCancelled;
- }
- public setCancelledTakerAmount(orderHash: string, cancelledTakerAmount: BigNumber): void {
- this._cancelledTakerAmount[orderHash] = cancelledTakerAmount;
- }
- public deleteCancelledTakerAmount(orderHash: string): void {
- delete this._cancelledTakerAmount[orderHash];
- }
- public deleteAll(): void {
- this._filledTakerAmount = {};
- this._cancelledTakerAmount = {};
- }
-}
diff --git a/packages/0x.js/src/types.ts b/packages/0x.js/src/types.ts
index ae9f98c5f..a8cf62c64 100644
--- a/packages/0x.js/src/types.ts
+++ b/packages/0x.js/src/types.ts
@@ -1,276 +1,20 @@
-import { BigNumber } from '@0xproject/utils';
-
import {
BlockParam,
BlockParamLiteral,
ContractAbi,
ContractEventArg,
+ ExchangeContractErrs,
FilterObject,
- LogEntryEvent,
LogWithDecodedArgs,
Order,
+ OrderState,
SignedOrder,
} from '@0xproject/types';
-import * as Web3 from 'web3';
-
-import { EtherTokenContractEventArgs, EtherTokenEvents } from './contract_wrappers/generated/ether_token';
-import { ExchangeContractEventArgs, ExchangeEvents } from './contract_wrappers/generated/exchange';
-import { TokenContractEventArgs, TokenEvents } from './contract_wrappers/generated/token';
-
-export enum ZeroExError {
- ExchangeContractDoesNotExist = 'EXCHANGE_CONTRACT_DOES_NOT_EXIST',
- ZRXContractDoesNotExist = 'ZRX_CONTRACT_DOES_NOT_EXIST',
- EtherTokenContractDoesNotExist = 'ETHER_TOKEN_CONTRACT_DOES_NOT_EXIST',
- TokenTransferProxyContractDoesNotExist = 'TOKEN_TRANSFER_PROXY_CONTRACT_DOES_NOT_EXIST',
- TokenRegistryContractDoesNotExist = 'TOKEN_REGISTRY_CONTRACT_DOES_NOT_EXIST',
- TokenContractDoesNotExist = 'TOKEN_CONTRACT_DOES_NOT_EXIST',
- UnhandledError = 'UNHANDLED_ERROR',
- UserHasNoAssociatedAddress = 'USER_HAS_NO_ASSOCIATED_ADDRESSES',
- ContractNotDeployedOnNetwork = 'CONTRACT_NOT_DEPLOYED_ON_NETWORK',
- InsufficientAllowanceForTransfer = 'INSUFFICIENT_ALLOWANCE_FOR_TRANSFER',
- InsufficientBalanceForTransfer = 'INSUFFICIENT_BALANCE_FOR_TRANSFER',
- InsufficientEthBalanceForDeposit = 'INSUFFICIENT_ETH_BALANCE_FOR_DEPOSIT',
- InsufficientWEthBalanceForWithdrawal = 'INSUFFICIENT_WETH_BALANCE_FOR_WITHDRAWAL',
- InvalidJump = 'INVALID_JUMP',
- OutOfGas = 'OUT_OF_GAS',
- NoNetworkId = 'NO_NETWORK_ID',
- SubscriptionNotFound = 'SUBSCRIPTION_NOT_FOUND',
- SubscriptionAlreadyPresent = 'SUBSCRIPTION_ALREADY_PRESENT',
-}
-
export enum InternalZeroExError {
NoAbiDecoder = 'NO_ABI_DECODER',
ZrxNotInTokenRegistry = 'ZRX_NOT_IN_TOKEN_REGISTRY',
WethNotInTokenRegistry = 'WETH_NOT_IN_TOKEN_REGISTRY',
}
-export type OrderAddresses = [string, string, string, string, string];
-
-export type OrderValues = [BigNumber, BigNumber, BigNumber, BigNumber, BigNumber, BigNumber];
-
-export type LogEvent = LogEntryEvent;
-export interface DecodedLogEvent<ArgsType> {
- isRemoved: boolean;
- log: LogWithDecodedArgs<ArgsType>;
-}
-
-export type EventCallback<ArgsType> = (err: null | Error, log?: DecodedLogEvent<ArgsType>) => void;
-export type EventWatcherCallback = (err: null | Error, log?: LogEvent) => void;
-
-export enum ExchangeContractErrCodes {
- ERROR_FILL_EXPIRED, // Order has already expired
- ERROR_FILL_NO_VALUE, // Order has already been fully filled or cancelled
- ERROR_FILL_TRUNCATION, // Rounding error too large
- ERROR_FILL_BALANCE_ALLOWANCE, // Insufficient balance or allowance for token transfer
- ERROR_CANCEL_EXPIRED, // Order has already expired
- ERROR_CANCEL_NO_VALUE, // Order has already been fully filled or cancelled
-}
-
-export enum ExchangeContractErrs {
- OrderFillExpired = 'ORDER_FILL_EXPIRED',
- OrderCancelExpired = 'ORDER_CANCEL_EXPIRED',
- OrderCancelAmountZero = 'ORDER_CANCEL_AMOUNT_ZERO',
- OrderAlreadyCancelledOrFilled = 'ORDER_ALREADY_CANCELLED_OR_FILLED',
- OrderFillAmountZero = 'ORDER_FILL_AMOUNT_ZERO',
- OrderRemainingFillAmountZero = 'ORDER_REMAINING_FILL_AMOUNT_ZERO',
- OrderFillRoundingError = 'ORDER_FILL_ROUNDING_ERROR',
- FillBalanceAllowanceError = 'FILL_BALANCE_ALLOWANCE_ERROR',
- InsufficientTakerBalance = 'INSUFFICIENT_TAKER_BALANCE',
- InsufficientTakerAllowance = 'INSUFFICIENT_TAKER_ALLOWANCE',
- InsufficientMakerBalance = 'INSUFFICIENT_MAKER_BALANCE',
- InsufficientMakerAllowance = 'INSUFFICIENT_MAKER_ALLOWANCE',
- InsufficientTakerFeeBalance = 'INSUFFICIENT_TAKER_FEE_BALANCE',
- InsufficientTakerFeeAllowance = 'INSUFFICIENT_TAKER_FEE_ALLOWANCE',
- InsufficientMakerFeeBalance = 'INSUFFICIENT_MAKER_FEE_BALANCE',
- InsufficientMakerFeeAllowance = 'INSUFFICIENT_MAKER_FEE_ALLOWANCE',
- TransactionSenderIsNotFillOrderTaker = 'TRANSACTION_SENDER_IS_NOT_FILL_ORDER_TAKER',
- MultipleMakersInSingleCancelBatchDisallowed = 'MULTIPLE_MAKERS_IN_SINGLE_CANCEL_BATCH_DISALLOWED',
- InsufficientRemainingFillAmount = 'INSUFFICIENT_REMAINING_FILL_AMOUNT',
- MultipleTakerTokensInFillUpToDisallowed = 'MULTIPLE_TAKER_TOKENS_IN_FILL_UP_TO_DISALLOWED',
- BatchOrdersMustHaveSameExchangeAddress = 'BATCH_ORDERS_MUST_HAVE_SAME_EXCHANGE_ADDRESS',
- BatchOrdersMustHaveAtLeastOneItem = 'BATCH_ORDERS_MUST_HAVE_AT_LEAST_ONE_ITEM',
-}
-
-export interface ContractEvent {
- logIndex: number;
- transactionIndex: number;
- transactionHash: string;
- blockHash: string;
- blockNumber: number;
- address: string;
- type: string;
- event: string;
- args: ContractEventArgs;
-}
-
-export type ContractEventArgs = ExchangeContractEventArgs | TokenContractEventArgs | EtherTokenContractEventArgs;
-
-// [address, name, symbol, decimals, ipfsHash, swarmHash]
-export type TokenMetadata = [string, string, string, number, string, string];
-
-export interface Token {
- name: string;
- address: string;
- symbol: string;
- decimals: number;
-}
-
-export interface TxOpts {
- from: string;
- gas?: number;
- value?: BigNumber;
- gasPrice?: BigNumber;
-}
-
-export interface TokenAddressBySymbol {
- [symbol: string]: string;
-}
-
-export type ContractEvents = TokenEvents | ExchangeEvents | EtherTokenEvents;
-
-export interface IndexedFilterValues {
- [index: string]: ContractEventArg;
-}
-
-export interface BlockRange {
- fromBlock: BlockParam;
- toBlock: BlockParam;
-}
-
-export type DoneCallback = (err?: Error) => void;
-
-export interface OrderCancellationRequest {
- order: Order | SignedOrder;
- takerTokenCancelAmount: BigNumber;
-}
-
-export interface OrderFillRequest {
- signedOrder: SignedOrder;
- takerTokenFillAmount: BigNumber;
-}
-
-export type AsyncMethod = (...args: any[]) => Promise<any>;
-export type SyncMethod = (...args: any[]) => any;
-
-/**
- * orderExpirationCheckingIntervalMs: How often to check for expired orders. Default=50.
- * eventPollingIntervalMs: How often to poll the Ethereum node for new events. Default=200.
- * expirationMarginMs: Amount of time before order expiry that you'd like to be notified
- * of an orders expiration. Default=0.
- * cleanupJobIntervalMs: How often to run a cleanup job which revalidates all the orders. Default=1hr.
- * stateLayer: Optional blockchain state layer OrderWatcher will monitor for new events. Default=latest.
- */
-export interface OrderStateWatcherConfig {
- orderExpirationCheckingIntervalMs?: number;
- eventPollingIntervalMs?: number;
- expirationMarginMs?: number;
- cleanupJobIntervalMs?: number;
- stateLayer: BlockParamLiteral;
-}
-
-/**
- * networkId: The id of the underlying ethereum network your provider is connected to. (1-mainnet, 3-ropsten, 4-rinkeby, 42-kovan, 50-testrpc)
- * gasPrice: Gas price to use with every transaction
- * exchangeContractAddress: The address of an exchange contract to use
- * zrxContractAddress: The address of the ZRX contract to use
- * tokenRegistryContractAddress: The address of a token registry contract to use
- * tokenTransferProxyContractAddress: The address of the token transfer proxy contract to use
- * orderWatcherConfig: All the configs related to the orderWatcher
- */
-export interface ZeroExConfig {
- networkId: number;
- gasPrice?: BigNumber;
- exchangeContractAddress?: string;
- zrxContractAddress?: string;
- tokenRegistryContractAddress?: string;
- tokenTransferProxyContractAddress?: string;
- orderWatcherConfig?: OrderStateWatcherConfig;
-}
-
-export type ArtifactContractName = 'ZRX' | 'TokenTransferProxy' | 'TokenRegistry' | 'Token' | 'Exchange' | 'EtherToken';
-
-export interface Artifact {
- contract_name: ArtifactContractName;
- abi: ContractAbi;
- networks: {
- [networkId: number]: {
- address: string;
- };
- };
-}
-
-/**
- * expectedFillTakerTokenAmount: If specified, the validation method will ensure that the
- * supplied order maker has a sufficient allowance/balance to fill this amount of the order's
- * takerTokenAmount. If not specified, the validation method ensures that the maker has a sufficient
- * allowance/balance to fill the entire remaining order amount.
- */
-export interface ValidateOrderFillableOpts {
- expectedFillTakerTokenAmount?: BigNumber;
-}
-
-/**
- * defaultBlock: The block up to which to query the blockchain state. Setting this to a historical block number
- * let's the user query the blockchain's state at an arbitrary point in time. In order for this to work, the
- * backing Ethereum node must keep the entire historical state of the chain (e.g setting `--pruning=archive`
- * flag when running Parity).
- */
-export interface MethodOpts {
- defaultBlock?: BlockParam;
-}
-
-/**
- * gasPrice: Gas price in Wei to use for a transaction
- * gasLimit: The amount of gas to send with a transaction
- */
-export interface TransactionOpts {
- gasPrice?: BigNumber;
- gasLimit?: number;
-}
-
-/**
- * shouldValidate: Flag indicating whether the library should make attempts to validate a transaction before
- * broadcasting it. For example, order has a valid signature, maker has sufficient funds, etc. Default=true.
- */
-export interface OrderTransactionOpts extends TransactionOpts {
- shouldValidate?: boolean;
-}
-
-export enum TradeSide {
- Maker = 'maker',
- Taker = 'taker',
-}
-
-export enum TransferType {
- Trade = 'trade',
- Fee = 'fee',
-}
-
-export interface OrderRelevantState {
- makerBalance: BigNumber;
- makerProxyAllowance: BigNumber;
- makerFeeBalance: BigNumber;
- makerFeeProxyAllowance: BigNumber;
- filledTakerTokenAmount: BigNumber;
- cancelledTakerTokenAmount: BigNumber;
- remainingFillableMakerTokenAmount: BigNumber;
- remainingFillableTakerTokenAmount: BigNumber;
-}
-
-export interface OrderStateValid {
- isValid: true;
- orderHash: string;
- orderRelevantState: OrderRelevantState;
-}
-
-export interface OrderStateInvalid {
- isValid: false;
- orderHash: string;
- error: ExchangeContractErrs;
-}
-
-export type OrderState = OrderStateValid | OrderStateInvalid;
-
-export type OnOrderStateChangeCallback = (err: Error | null, orderState?: OrderState) => void;
// tslint:disable:max-file-line-count
diff --git a/packages/0x.js/src/utils/assert.ts b/packages/0x.js/src/utils/assert.ts
deleted file mode 100644
index 2588a4d09..000000000
--- a/packages/0x.js/src/utils/assert.ts
+++ /dev/null
@@ -1,31 +0,0 @@
-import { assert as sharedAssert } from '@0xproject/assert';
-// We need those two unused imports because they're actually used by sharedAssert which gets injected here
-// tslint:disable-next-line:no-unused-variable
-import { Schema } from '@0xproject/json-schemas';
-// tslint:disable-next-line:no-unused-variable
-import { ECSignature } from '@0xproject/types';
-import { BigNumber } from '@0xproject/utils';
-import { Web3Wrapper } from '@0xproject/web3-wrapper';
-import * as _ from 'lodash';
-
-import { isValidSignature } from '@0xproject/order-utils';
-
-export const assert = {
- ...sharedAssert,
- isValidSignature(orderHash: string, ecSignature: ECSignature, signerAddress: string) {
- const isValid = isValidSignature(orderHash, ecSignature, signerAddress);
- this.assert(isValid, `Expected order with hash '${orderHash}' to have a valid signature`);
- },
- async isSenderAddressAsync(
- variableName: string,
- senderAddressHex: string,
- web3Wrapper: Web3Wrapper,
- ): Promise<void> {
- sharedAssert.isETHAddressHex(variableName, senderAddressHex);
- const isSenderAddressAvailable = await web3Wrapper.isSenderAddressAvailableAsync(senderAddressHex);
- sharedAssert.assert(
- isSenderAddressAvailable,
- `Specified ${variableName} ${senderAddressHex} isn't available through the supplied web3 provider`,
- );
- },
-};
diff --git a/packages/0x.js/src/utils/constants.ts b/packages/0x.js/src/utils/constants.ts
index 07da6745d..7cd5eb574 100644
--- a/packages/0x.js/src/utils/constants.ts
+++ b/packages/0x.js/src/utils/constants.ts
@@ -3,9 +3,4 @@ import { BigNumber } from '@0xproject/utils';
export const constants = {
NULL_ADDRESS: '0x0000000000000000000000000000000000000000',
TESTRPC_NETWORK_ID: 50,
- INVALID_JUMP_PATTERN: 'invalid JUMP at',
- OUT_OF_GAS_PATTERN: 'out of gas',
- INVALID_TAKER_FORMAT: 'instance.taker is not of a type(s) string',
- UNLIMITED_ALLOWANCE_IN_BASE_UNITS: new BigNumber(2).pow(256).minus(1),
- DEFAULT_BLOCK_POLLING_INTERVAL: 1000,
};
diff --git a/packages/0x.js/src/utils/decorators.ts b/packages/0x.js/src/utils/decorators.ts
deleted file mode 100644
index f774d734e..000000000
--- a/packages/0x.js/src/utils/decorators.ts
+++ /dev/null
@@ -1,91 +0,0 @@
-import * as _ from 'lodash';
-
-import { AsyncMethod, SyncMethod, ZeroExError } from '../types';
-
-import { constants } from './constants';
-
-type ErrorTransformer = (err: Error) => Error;
-
-const contractCallErrorTransformer = (error: Error) => {
- if (_.includes(error.message, constants.INVALID_JUMP_PATTERN)) {
- return new Error(ZeroExError.InvalidJump);
- }
- if (_.includes(error.message, constants.OUT_OF_GAS_PATTERN)) {
- return new Error(ZeroExError.OutOfGas);
- }
- return error;
-};
-
-const schemaErrorTransformer = (error: Error) => {
- if (_.includes(error.message, constants.INVALID_TAKER_FORMAT)) {
- 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 error;
-};
-
-/**
- * Source: https://stackoverflow.com/a/29837695/3546986
- */
-const asyncErrorHandlerFactory = (errorTransformer: ErrorTransformer) => {
- const asyncErrorHandlingDecorator = (
- target: object,
- key: string | symbol,
- descriptor: TypedPropertyDescriptor<AsyncMethod>,
- ) => {
- const originalMethod = descriptor.value as AsyncMethod;
-
- // Do not use arrow syntax here. Use a function expression in
- // order to use the correct value of `this` in this method
- // tslint:disable-next-line:only-arrow-functions
- descriptor.value = async function(...args: any[]) {
- try {
- const result = await originalMethod.apply(this, args);
- return result;
- } catch (error) {
- const transformedError = errorTransformer(error);
- throw transformedError;
- }
- };
-
- return descriptor;
- };
-
- return asyncErrorHandlingDecorator;
-};
-
-const syncErrorHandlerFactory = (errorTransformer: ErrorTransformer) => {
- const syncErrorHandlingDecorator = (
- target: object,
- key: string | symbol,
- descriptor: TypedPropertyDescriptor<SyncMethod>,
- ) => {
- const originalMethod = descriptor.value as SyncMethod;
-
- // Do not use arrow syntax here. Use a function expression in
- // order to use the correct value of `this` in this method
- // tslint:disable-next-line:only-arrow-functions
- descriptor.value = function(...args: any[]) {
- try {
- const result = originalMethod.apply(this, args);
- return result;
- } catch (error) {
- const transformedError = errorTransformer(error);
- throw transformedError;
- }
- };
-
- return descriptor;
- };
-
- return syncErrorHandlingDecorator;
-};
-
-// _.flow(f, g) = f ∘ g
-const zeroExErrorTransformer = _.flow(schemaErrorTransformer, contractCallErrorTransformer);
-
-export const decorators = {
- asyncZeroExErrorHandler: asyncErrorHandlerFactory(zeroExErrorTransformer),
- syncZeroExErrorHandler: syncErrorHandlerFactory(zeroExErrorTransformer),
-};
diff --git a/packages/0x.js/src/utils/exchange_transfer_simulator.ts b/packages/0x.js/src/utils/exchange_transfer_simulator.ts
deleted file mode 100644
index f8301f5c2..000000000
--- a/packages/0x.js/src/utils/exchange_transfer_simulator.ts
+++ /dev/null
@@ -1,115 +0,0 @@
-import { BlockParamLiteral } from '@0xproject/types';
-import { BigNumber } from '@0xproject/utils';
-import * as _ from 'lodash';
-
-import { TokenWrapper } from '../contract_wrappers/token_wrapper';
-import { BalanceAndProxyAllowanceLazyStore } from '../stores/balance_proxy_allowance_lazy_store';
-import { ExchangeContractErrs, TradeSide, TransferType } from '../types';
-import { constants } from '../utils/constants';
-
-enum FailureReason {
- Balance = 'balance',
- ProxyAllowance = 'proxyAllowance',
-}
-
-const ERR_MSG_MAPPING = {
- [FailureReason.Balance]: {
- [TradeSide.Maker]: {
- [TransferType.Trade]: ExchangeContractErrs.InsufficientMakerBalance,
- [TransferType.Fee]: ExchangeContractErrs.InsufficientMakerFeeBalance,
- },
- [TradeSide.Taker]: {
- [TransferType.Trade]: ExchangeContractErrs.InsufficientTakerBalance,
- [TransferType.Fee]: ExchangeContractErrs.InsufficientTakerFeeBalance,
- },
- },
- [FailureReason.ProxyAllowance]: {
- [TradeSide.Maker]: {
- [TransferType.Trade]: ExchangeContractErrs.InsufficientMakerAllowance,
- [TransferType.Fee]: ExchangeContractErrs.InsufficientMakerFeeAllowance,
- },
- [TradeSide.Taker]: {
- [TransferType.Trade]: ExchangeContractErrs.InsufficientTakerAllowance,
- [TransferType.Fee]: ExchangeContractErrs.InsufficientTakerFeeAllowance,
- },
- },
-};
-
-export class ExchangeTransferSimulator {
- private _store: BalanceAndProxyAllowanceLazyStore;
- private _UNLIMITED_ALLOWANCE_IN_BASE_UNITS: BigNumber;
- private static _throwValidationError(
- failureReason: FailureReason,
- tradeSide: TradeSide,
- transferType: TransferType,
- ): never {
- const errMsg = ERR_MSG_MAPPING[failureReason][tradeSide][transferType];
- throw new Error(errMsg);
- }
- constructor(token: TokenWrapper, defaultBlock: BlockParamLiteral) {
- this._store = new BalanceAndProxyAllowanceLazyStore(token, defaultBlock);
- this._UNLIMITED_ALLOWANCE_IN_BASE_UNITS = token.UNLIMITED_ALLOWANCE_IN_BASE_UNITS;
- }
- /**
- * Simulates transferFrom call performed by a proxy
- * @param tokenAddress Address of the token to be transferred
- * @param from Owner of the transferred tokens
- * @param to Recipient of the transferred tokens
- * @param amountInBaseUnits The amount of tokens being transferred
- * @param tradeSide Is Maker/Taker transferring
- * @param transferType Is it a fee payment or a value transfer
- */
- public async transferFromAsync(
- tokenAddress: string,
- from: string,
- to: string,
- amountInBaseUnits: BigNumber,
- tradeSide: TradeSide,
- transferType: TransferType,
- ): Promise<void> {
- // HACK: When simulating an open order (e.g taker is NULL_ADDRESS), we don't want to adjust balances/
- // allowances for the taker. We do however, want to increase the balance of the maker since the maker
- // might be relying on those funds to fill subsequent orders or pay the order's fees.
- if (from === constants.NULL_ADDRESS && tradeSide === TradeSide.Taker) {
- await this._increaseBalanceAsync(tokenAddress, to, amountInBaseUnits);
- return;
- }
- const balance = await this._store.getBalanceAsync(tokenAddress, from);
- const proxyAllowance = await this._store.getProxyAllowanceAsync(tokenAddress, from);
- if (proxyAllowance.lessThan(amountInBaseUnits)) {
- ExchangeTransferSimulator._throwValidationError(FailureReason.ProxyAllowance, tradeSide, transferType);
- }
- if (balance.lessThan(amountInBaseUnits)) {
- ExchangeTransferSimulator._throwValidationError(FailureReason.Balance, tradeSide, transferType);
- }
- await this._decreaseProxyAllowanceAsync(tokenAddress, from, amountInBaseUnits);
- await this._decreaseBalanceAsync(tokenAddress, from, amountInBaseUnits);
- await this._increaseBalanceAsync(tokenAddress, to, amountInBaseUnits);
- }
- private async _decreaseProxyAllowanceAsync(
- tokenAddress: string,
- userAddress: string,
- amountInBaseUnits: BigNumber,
- ): Promise<void> {
- const proxyAllowance = await this._store.getProxyAllowanceAsync(tokenAddress, userAddress);
- if (!proxyAllowance.eq(this._UNLIMITED_ALLOWANCE_IN_BASE_UNITS)) {
- this._store.setProxyAllowance(tokenAddress, userAddress, proxyAllowance.minus(amountInBaseUnits));
- }
- }
- private async _increaseBalanceAsync(
- tokenAddress: string,
- userAddress: string,
- amountInBaseUnits: BigNumber,
- ): Promise<void> {
- const balance = await this._store.getBalanceAsync(tokenAddress, userAddress);
- this._store.setBalance(tokenAddress, userAddress, balance.plus(amountInBaseUnits));
- }
- private async _decreaseBalanceAsync(
- tokenAddress: string,
- userAddress: string,
- amountInBaseUnits: BigNumber,
- ): Promise<void> {
- const balance = await this._store.getBalanceAsync(tokenAddress, userAddress);
- this._store.setBalance(tokenAddress, userAddress, balance.minus(amountInBaseUnits));
- }
-}
diff --git a/packages/0x.js/src/utils/filter_utils.ts b/packages/0x.js/src/utils/filter_utils.ts
deleted file mode 100644
index c5df7321e..000000000
--- a/packages/0x.js/src/utils/filter_utils.ts
+++ /dev/null
@@ -1,95 +0,0 @@
-import {
- ConstructorAbi,
- ContractAbi,
- EventAbi,
- FallbackAbi,
- FilterObject,
- LogEntry,
- MethodAbi,
-} from '@0xproject/types';
-import * as ethUtil from 'ethereumjs-util';
-import * as jsSHA3 from 'js-sha3';
-import * as _ from 'lodash';
-import * as uuid from 'uuid/v4';
-
-import { BlockRange, ContractEvents, IndexedFilterValues } from '../types';
-
-const TOPIC_LENGTH = 32;
-
-export const filterUtils = {
- generateUUID(): string {
- return uuid();
- },
- getFilter(
- address: string,
- eventName: ContractEvents,
- indexFilterValues: IndexedFilterValues,
- abi: ContractAbi,
- blockRange?: BlockRange,
- ): FilterObject {
- const eventAbi = _.find(abi, { name: eventName }) as EventAbi;
- const eventSignature = filterUtils.getEventSignatureFromAbiByName(eventAbi, eventName);
- const topicForEventSignature = ethUtil.addHexPrefix(jsSHA3.keccak256(eventSignature));
- const topicsForIndexedArgs = filterUtils.getTopicsForIndexedArgs(eventAbi, indexFilterValues);
- const topics = [topicForEventSignature, ...topicsForIndexedArgs];
- let filter: FilterObject = {
- address,
- topics,
- };
- if (!_.isUndefined(blockRange)) {
- filter = {
- ...blockRange,
- ...filter,
- };
- }
- return filter;
- },
- getEventSignatureFromAbiByName(eventAbi: EventAbi, eventName: ContractEvents): string {
- const types = _.map(eventAbi.inputs, 'type');
- const signature = `${eventAbi.name}(${types.join(',')})`;
- return signature;
- },
- getTopicsForIndexedArgs(abi: EventAbi, indexFilterValues: IndexedFilterValues): Array<string | null> {
- const topics: Array<string | null> = [];
- for (const eventInput of abi.inputs) {
- if (!eventInput.indexed) {
- continue;
- }
- if (_.isUndefined(indexFilterValues[eventInput.name])) {
- // Null is a wildcard topic in a JSON-RPC call
- topics.push(null);
- } else {
- const value = indexFilterValues[eventInput.name] as string;
- const buffer = ethUtil.toBuffer(value);
- const paddedBuffer = ethUtil.setLengthLeft(buffer, TOPIC_LENGTH);
- const topic = ethUtil.bufferToHex(paddedBuffer);
- topics.push(topic);
- }
- }
- return topics;
- },
- matchesFilter(log: LogEntry, filter: FilterObject): boolean {
- if (!_.isUndefined(filter.address) && log.address !== filter.address) {
- return false;
- }
- if (!_.isUndefined(filter.topics)) {
- return filterUtils.matchesTopics(log.topics, filter.topics);
- }
- return true;
- },
- matchesTopics(logTopics: string[], filterTopics: Array<string[] | string | null>): boolean {
- const matchesTopic = _.zipWith(logTopics, filterTopics, filterUtils.matchesTopic.bind(filterUtils));
- const matchesTopics = _.every(matchesTopic);
- return matchesTopics;
- },
- matchesTopic(logTopic: string, filterTopic: string[] | string | null): boolean {
- if (_.isArray(filterTopic)) {
- return _.includes(filterTopic, logTopic);
- }
- if (_.isString(filterTopic)) {
- return filterTopic === logTopic;
- }
- // null topic is a wildcard
- return true;
- },
-};
diff --git a/packages/0x.js/src/utils/order_state_utils.ts b/packages/0x.js/src/utils/order_state_utils.ts
deleted file mode 100644
index b0310d8a8..000000000
--- a/packages/0x.js/src/utils/order_state_utils.ts
+++ /dev/null
@@ -1,138 +0,0 @@
-import { SignedOrder } from '@0xproject/types';
-import { BigNumber } from '@0xproject/utils';
-import * as _ from 'lodash';
-
-import { ZeroEx } from '../0x';
-import { BalanceAndProxyAllowanceFetcher } from '../abstract/balance_and_proxy_allowance_fetcher';
-import { OrderFilledCancelledFetcher } from '../abstract/order_filled_cancelled_fetcher';
-import { ExchangeWrapper } from '../contract_wrappers/exchange_wrapper';
-import { RemainingFillableCalculator } from '../order_watcher/remaining_fillable_calculator';
-import { ExchangeContractErrs, OrderRelevantState, OrderState, OrderStateInvalid, OrderStateValid } from '../types';
-
-const ACCEPTABLE_RELATIVE_ROUNDING_ERROR = 0.0001;
-
-export class OrderStateUtils {
- private _balanceAndProxyAllowanceFetcher: BalanceAndProxyAllowanceFetcher;
- private _orderFilledCancelledFetcher: OrderFilledCancelledFetcher;
- private static _validateIfOrderIsValid(signedOrder: SignedOrder, orderRelevantState: OrderRelevantState): void {
- const unavailableTakerTokenAmount = orderRelevantState.cancelledTakerTokenAmount.add(
- orderRelevantState.filledTakerTokenAmount,
- );
- const availableTakerTokenAmount = signedOrder.takerTokenAmount.minus(unavailableTakerTokenAmount);
- if (availableTakerTokenAmount.eq(0)) {
- throw new Error(ExchangeContractErrs.OrderRemainingFillAmountZero);
- }
-
- if (orderRelevantState.makerBalance.eq(0)) {
- throw new Error(ExchangeContractErrs.InsufficientMakerBalance);
- }
- if (orderRelevantState.makerProxyAllowance.eq(0)) {
- throw new Error(ExchangeContractErrs.InsufficientMakerAllowance);
- }
- if (!signedOrder.makerFee.eq(0)) {
- if (orderRelevantState.makerFeeBalance.eq(0)) {
- throw new Error(ExchangeContractErrs.InsufficientMakerFeeBalance);
- }
- if (orderRelevantState.makerFeeProxyAllowance.eq(0)) {
- throw new Error(ExchangeContractErrs.InsufficientMakerFeeAllowance);
- }
- }
- const minFillableTakerTokenAmountWithinNoRoundingErrorRange = signedOrder.takerTokenAmount
- .dividedBy(ACCEPTABLE_RELATIVE_ROUNDING_ERROR)
- .dividedBy(signedOrder.makerTokenAmount);
- if (
- orderRelevantState.remainingFillableTakerTokenAmount.lessThan(
- minFillableTakerTokenAmountWithinNoRoundingErrorRange,
- )
- ) {
- throw new Error(ExchangeContractErrs.OrderFillRoundingError);
- }
- }
- constructor(
- balanceAndProxyAllowanceFetcher: BalanceAndProxyAllowanceFetcher,
- orderFilledCancelledFetcher: OrderFilledCancelledFetcher,
- ) {
- this._balanceAndProxyAllowanceFetcher = balanceAndProxyAllowanceFetcher;
- this._orderFilledCancelledFetcher = orderFilledCancelledFetcher;
- }
- public async getOrderStateAsync(signedOrder: SignedOrder): Promise<OrderState> {
- const orderRelevantState = await this.getOrderRelevantStateAsync(signedOrder);
- const orderHash = ZeroEx.getOrderHashHex(signedOrder);
- try {
- OrderStateUtils._validateIfOrderIsValid(signedOrder, orderRelevantState);
- const orderState: OrderStateValid = {
- isValid: true,
- orderHash,
- orderRelevantState,
- };
- return orderState;
- } catch (err) {
- const orderState: OrderStateInvalid = {
- isValid: false,
- orderHash,
- error: err.message,
- };
- return orderState;
- }
- }
- public async getOrderRelevantStateAsync(signedOrder: SignedOrder): Promise<OrderRelevantState> {
- // HACK: We access the private property here but otherwise the interface will be less nice.
- // If we pass it from the instantiator - there is no opportunity to get it there
- // because JS doesn't support async constructors.
- // Moreover - it's cached under the hood so it's equivalent to an async constructor.
- const exchange = (this._orderFilledCancelledFetcher as any)._exchangeWrapper as ExchangeWrapper;
- const zrxTokenAddress = exchange.getZRXTokenAddress();
- const orderHash = ZeroEx.getOrderHashHex(signedOrder);
- const makerBalance = await this._balanceAndProxyAllowanceFetcher.getBalanceAsync(
- signedOrder.makerTokenAddress,
- signedOrder.maker,
- );
- const makerProxyAllowance = await this._balanceAndProxyAllowanceFetcher.getProxyAllowanceAsync(
- signedOrder.makerTokenAddress,
- signedOrder.maker,
- );
- const makerFeeBalance = await this._balanceAndProxyAllowanceFetcher.getBalanceAsync(
- zrxTokenAddress,
- signedOrder.maker,
- );
- const makerFeeProxyAllowance = await this._balanceAndProxyAllowanceFetcher.getProxyAllowanceAsync(
- zrxTokenAddress,
- signedOrder.maker,
- );
- const filledTakerTokenAmount = await this._orderFilledCancelledFetcher.getFilledTakerAmountAsync(orderHash);
- const cancelledTakerTokenAmount = await this._orderFilledCancelledFetcher.getCancelledTakerAmountAsync(
- orderHash,
- );
- const unavailableTakerTokenAmount = await exchange.getUnavailableTakerAmountAsync(orderHash);
- const totalMakerTokenAmount = signedOrder.makerTokenAmount;
- const totalTakerTokenAmount = signedOrder.takerTokenAmount;
- const remainingTakerTokenAmount = totalTakerTokenAmount.minus(unavailableTakerTokenAmount);
- const remainingMakerTokenAmount = remainingTakerTokenAmount
- .times(totalMakerTokenAmount)
- .dividedToIntegerBy(totalTakerTokenAmount);
- const transferrableMakerTokenAmount = BigNumber.min([makerProxyAllowance, makerBalance]);
- const transferrableFeeTokenAmount = BigNumber.min([makerFeeProxyAllowance, makerFeeBalance]);
-
- const isMakerTokenZRX = signedOrder.makerTokenAddress === zrxTokenAddress;
- const remainingFillableCalculator = new RemainingFillableCalculator(
- signedOrder,
- isMakerTokenZRX,
- transferrableMakerTokenAmount,
- transferrableFeeTokenAmount,
- remainingMakerTokenAmount,
- );
- const remainingFillableMakerTokenAmount = remainingFillableCalculator.computeRemainingMakerFillable();
- const remainingFillableTakerTokenAmount = remainingFillableCalculator.computeRemainingTakerFillable();
- const orderRelevantState = {
- makerBalance,
- makerProxyAllowance,
- makerFeeBalance,
- makerFeeProxyAllowance,
- filledTakerTokenAmount,
- cancelledTakerTokenAmount,
- remainingFillableMakerTokenAmount,
- remainingFillableTakerTokenAmount,
- };
- return orderRelevantState;
- }
-}
diff --git a/packages/0x.js/src/utils/order_validation_utils.ts b/packages/0x.js/src/utils/order_validation_utils.ts
deleted file mode 100644
index a13c3dc04..000000000
--- a/packages/0x.js/src/utils/order_validation_utils.ts
+++ /dev/null
@@ -1,199 +0,0 @@
-import { getOrderHashHex, OrderError } from '@0xproject/order-utils';
-import { Order, SignedOrder } from '@0xproject/types';
-import { BigNumber } from '@0xproject/utils';
-import * as _ from 'lodash';
-
-import { ZeroEx } from '../0x';
-import { ExchangeWrapper } from '../contract_wrappers/exchange_wrapper';
-import { ExchangeContractErrs, TradeSide, TransferType, ZeroExError } from '../types';
-import { constants } from '../utils/constants';
-import { utils } from '../utils/utils';
-
-import { ExchangeTransferSimulator } from './exchange_transfer_simulator';
-
-export class OrderValidationUtils {
- private _exchangeWrapper: ExchangeWrapper;
- public static validateCancelOrderThrowIfInvalid(
- order: Order,
- cancelTakerTokenAmount: BigNumber,
- unavailableTakerTokenAmount: BigNumber,
- ): void {
- if (cancelTakerTokenAmount.eq(0)) {
- throw new Error(ExchangeContractErrs.OrderCancelAmountZero);
- }
- if (order.takerTokenAmount.eq(unavailableTakerTokenAmount)) {
- throw new Error(ExchangeContractErrs.OrderAlreadyCancelledOrFilled);
- }
- const currentUnixTimestampSec = utils.getCurrentUnixTimestampSec();
- if (order.expirationUnixTimestampSec.lessThan(currentUnixTimestampSec)) {
- throw new Error(ExchangeContractErrs.OrderCancelExpired);
- }
- }
- public static async validateFillOrderBalancesAllowancesThrowIfInvalidAsync(
- exchangeTradeEmulator: ExchangeTransferSimulator,
- signedOrder: SignedOrder,
- fillTakerTokenAmount: BigNumber,
- senderAddress: string,
- zrxTokenAddress: string,
- ): Promise<void> {
- const fillMakerTokenAmount = OrderValidationUtils._getPartialAmount(
- fillTakerTokenAmount,
- signedOrder.takerTokenAmount,
- signedOrder.makerTokenAmount,
- );
- await exchangeTradeEmulator.transferFromAsync(
- signedOrder.makerTokenAddress,
- signedOrder.maker,
- senderAddress,
- fillMakerTokenAmount,
- TradeSide.Maker,
- TransferType.Trade,
- );
- await exchangeTradeEmulator.transferFromAsync(
- signedOrder.takerTokenAddress,
- senderAddress,
- signedOrder.maker,
- fillTakerTokenAmount,
- TradeSide.Taker,
- TransferType.Trade,
- );
- const makerFeeAmount = OrderValidationUtils._getPartialAmount(
- fillTakerTokenAmount,
- signedOrder.takerTokenAmount,
- signedOrder.makerFee,
- );
- await exchangeTradeEmulator.transferFromAsync(
- zrxTokenAddress,
- signedOrder.maker,
- signedOrder.feeRecipient,
- makerFeeAmount,
- TradeSide.Maker,
- TransferType.Fee,
- );
- const takerFeeAmount = OrderValidationUtils._getPartialAmount(
- fillTakerTokenAmount,
- signedOrder.takerTokenAmount,
- signedOrder.takerFee,
- );
- await exchangeTradeEmulator.transferFromAsync(
- zrxTokenAddress,
- senderAddress,
- signedOrder.feeRecipient,
- takerFeeAmount,
- TradeSide.Taker,
- TransferType.Fee,
- );
- }
- private static _validateRemainingFillAmountNotZeroOrThrow(
- takerTokenAmount: BigNumber,
- unavailableTakerTokenAmount: BigNumber,
- ) {
- if (takerTokenAmount.eq(unavailableTakerTokenAmount)) {
- throw new Error(ExchangeContractErrs.OrderRemainingFillAmountZero);
- }
- }
- private static _validateOrderNotExpiredOrThrow(expirationUnixTimestampSec: BigNumber) {
- const currentUnixTimestampSec = utils.getCurrentUnixTimestampSec();
- if (expirationUnixTimestampSec.lessThan(currentUnixTimestampSec)) {
- throw new Error(ExchangeContractErrs.OrderFillExpired);
- }
- }
- private static _getPartialAmount(numerator: BigNumber, denominator: BigNumber, target: BigNumber): BigNumber {
- const fillMakerTokenAmount = numerator
- .mul(target)
- .div(denominator)
- .round(0);
- return fillMakerTokenAmount;
- }
- constructor(exchangeWrapper: ExchangeWrapper) {
- this._exchangeWrapper = exchangeWrapper;
- }
- public async validateOrderFillableOrThrowAsync(
- exchangeTradeEmulator: ExchangeTransferSimulator,
- signedOrder: SignedOrder,
- zrxTokenAddress: string,
- expectedFillTakerTokenAmount?: BigNumber,
- ): Promise<void> {
- const orderHash = getOrderHashHex(signedOrder);
- const unavailableTakerTokenAmount = await this._exchangeWrapper.getUnavailableTakerAmountAsync(orderHash);
- OrderValidationUtils._validateRemainingFillAmountNotZeroOrThrow(
- signedOrder.takerTokenAmount,
- unavailableTakerTokenAmount,
- );
- OrderValidationUtils._validateOrderNotExpiredOrThrow(signedOrder.expirationUnixTimestampSec);
- let fillTakerTokenAmount = signedOrder.takerTokenAmount.minus(unavailableTakerTokenAmount);
- if (!_.isUndefined(expectedFillTakerTokenAmount)) {
- fillTakerTokenAmount = expectedFillTakerTokenAmount;
- }
- await OrderValidationUtils.validateFillOrderBalancesAllowancesThrowIfInvalidAsync(
- exchangeTradeEmulator,
- signedOrder,
- fillTakerTokenAmount,
- signedOrder.taker,
- zrxTokenAddress,
- );
- }
- public async validateFillOrderThrowIfInvalidAsync(
- exchangeTradeEmulator: ExchangeTransferSimulator,
- signedOrder: SignedOrder,
- fillTakerTokenAmount: BigNumber,
- takerAddress: string,
- zrxTokenAddress: string,
- ): Promise<BigNumber> {
- if (fillTakerTokenAmount.eq(0)) {
- throw new Error(ExchangeContractErrs.OrderFillAmountZero);
- }
- const orderHash = getOrderHashHex(signedOrder);
- if (!ZeroEx.isValidSignature(orderHash, signedOrder.ecSignature, signedOrder.maker)) {
- throw new Error(OrderError.InvalidSignature);
- }
- const unavailableTakerTokenAmount = await this._exchangeWrapper.getUnavailableTakerAmountAsync(orderHash);
- OrderValidationUtils._validateRemainingFillAmountNotZeroOrThrow(
- signedOrder.takerTokenAmount,
- unavailableTakerTokenAmount,
- );
- if (signedOrder.taker !== constants.NULL_ADDRESS && signedOrder.taker !== takerAddress) {
- throw new Error(ExchangeContractErrs.TransactionSenderIsNotFillOrderTaker);
- }
- OrderValidationUtils._validateOrderNotExpiredOrThrow(signedOrder.expirationUnixTimestampSec);
- const remainingTakerTokenAmount = signedOrder.takerTokenAmount.minus(unavailableTakerTokenAmount);
- const filledTakerTokenAmount = remainingTakerTokenAmount.lessThan(fillTakerTokenAmount)
- ? remainingTakerTokenAmount
- : fillTakerTokenAmount;
- await OrderValidationUtils.validateFillOrderBalancesAllowancesThrowIfInvalidAsync(
- exchangeTradeEmulator,
- signedOrder,
- filledTakerTokenAmount,
- takerAddress,
- zrxTokenAddress,
- );
-
- const wouldRoundingErrorOccur = await this._exchangeWrapper.isRoundingErrorAsync(
- filledTakerTokenAmount,
- signedOrder.takerTokenAmount,
- signedOrder.makerTokenAmount,
- );
- if (wouldRoundingErrorOccur) {
- throw new Error(ExchangeContractErrs.OrderFillRoundingError);
- }
- return filledTakerTokenAmount;
- }
- public async validateFillOrKillOrderThrowIfInvalidAsync(
- exchangeTradeEmulator: ExchangeTransferSimulator,
- signedOrder: SignedOrder,
- fillTakerTokenAmount: BigNumber,
- takerAddress: string,
- zrxTokenAddress: string,
- ): Promise<void> {
- const filledTakerTokenAmount = await this.validateFillOrderThrowIfInvalidAsync(
- exchangeTradeEmulator,
- signedOrder,
- fillTakerTokenAmount,
- takerAddress,
- zrxTokenAddress,
- );
- if (filledTakerTokenAmount !== fillTakerTokenAmount) {
- throw new Error(ExchangeContractErrs.InsufficientRemainingFillAmount);
- }
- }
-}
diff --git a/packages/0x.js/src/utils/utils.ts b/packages/0x.js/src/utils/utils.ts
deleted file mode 100644
index af1125632..000000000
--- a/packages/0x.js/src/utils/utils.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-import { BigNumber } from '@0xproject/utils';
-
-export const utils = {
- spawnSwitchErr(name: string, value: any): Error {
- return new Error(`Unexpected switch value: ${value} encountered for ${name}`);
- },
- getCurrentUnixTimestampSec(): BigNumber {
- return new BigNumber(Date.now() / 1000).round();
- },
- getCurrentUnixTimestampMs(): BigNumber {
- return new BigNumber(Date.now());
- },
-};
diff --git a/packages/0x.js/test/0x.js_test.ts b/packages/0x.js/test/0x.js_test.ts
index 6dccdaea7..ce2fa34bf 100644
--- a/packages/0x.js/test/0x.js_test.ts
+++ b/packages/0x.js/test/0x.js_test.ts
@@ -1,3 +1,4 @@
+import { ContractWrappers } from '@0xproject/contract-wrappers';
import { BlockchainLifecycle, devConstants, web3Factory } from '@0xproject/dev-utils';
import { BigNumber } from '@0xproject/utils';
import * as chai from 'chai';
@@ -41,9 +42,9 @@ describe('ZeroEx library', () => {
expect((zeroEx.exchange as any)._exchangeContractIfExists).to.be.undefined();
expect((zeroEx.tokenRegistry as any)._tokenRegistryContractIfExists).to.be.undefined();
- // Check that all nested web3 wrapper instances return the updated provider
- const nestedWeb3WrapperProvider = (zeroEx as any)._web3Wrapper.getProvider();
- expect(nestedWeb3WrapperProvider.zeroExTestId).to.be.a('number');
+ // Check that all nested zeroExContract/web3Wrapper instances return the updated provider
+ const nestedWeb3WrapperProvider = ((zeroEx as any)._contractWrappers as ContractWrappers).getProvider();
+ expect((nestedWeb3WrapperProvider as any).zeroExTestId).to.be.a('number');
const exchangeWeb3WrapperProvider = (zeroEx.exchange as any)._web3Wrapper.getProvider();
expect(exchangeWeb3WrapperProvider.zeroExTestId).to.be.a('number');
const tokenRegistryWeb3WrapperProvider = (zeroEx.tokenRegistry as any)._web3Wrapper.getProvider();
diff --git a/packages/0x.js/test/assert_test.ts b/packages/0x.js/test/assert_test.ts
deleted file mode 100644
index e69de29bb..000000000
--- a/packages/0x.js/test/assert_test.ts
+++ /dev/null
diff --git a/packages/0x.js/test/ether_token_wrapper_test.ts b/packages/0x.js/test/ether_token_wrapper_test.ts
deleted file mode 100644
index 99c42fe0b..000000000
--- a/packages/0x.js/test/ether_token_wrapper_test.ts
+++ /dev/null
@@ -1,386 +0,0 @@
-import { BlockchainLifecycle, devConstants, web3Factory } from '@0xproject/dev-utils';
-import { BigNumber } from '@0xproject/utils';
-import { Web3Wrapper } from '@0xproject/web3-wrapper';
-import * as chai from 'chai';
-import 'mocha';
-
-import {
- ApprovalContractEventArgs,
- BlockParamLiteral,
- BlockRange,
- DecodedLogEvent,
- DepositContractEventArgs,
- EtherTokenEvents,
- Token,
- TransferContractEventArgs,
- WithdrawalContractEventArgs,
- ZeroEx,
- ZeroExError,
-} from '../src';
-import { DoneCallback } from '../src/types';
-
-import { chaiSetup } from './utils/chai_setup';
-import { constants } from './utils/constants';
-import { reportNodeCallbackErrors } from './utils/report_callback_errors';
-import { TokenUtils } from './utils/token_utils';
-import { provider, web3Wrapper } from './utils/web3_wrapper';
-
-chaiSetup.configure();
-const expect = chai.expect;
-const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
-
-// Since the address depositing/withdrawing ETH/WETH also needs to pay gas costs for the transaction,
-// a small amount of ETH will be used to pay this gas cost. We therefore check that the difference between
-// the expected balance and actual balance (given the amount of ETH deposited), only deviates by the amount
-// required to pay gas costs.
-const MAX_REASONABLE_GAS_COST_IN_WEI = 62517;
-
-describe('EtherTokenWrapper', () => {
- let zeroEx: ZeroEx;
- let tokens: Token[];
- let userAddresses: string[];
- let addressWithETH: string;
- let wethContractAddress: string;
- let depositWeiAmount: BigNumber;
- let decimalPlaces: number;
- let addressWithoutFunds: string;
- const gasPrice = new BigNumber(1);
- const zeroExConfig = {
- gasPrice,
- networkId: constants.TESTRPC_NETWORK_ID,
- };
- const transferAmount = new BigNumber(42);
- const allowanceAmount = new BigNumber(42);
- const depositAmount = new BigNumber(42);
- const withdrawalAmount = new BigNumber(42);
- before(async () => {
- zeroEx = new ZeroEx(provider, zeroExConfig);
- tokens = await zeroEx.tokenRegistry.getTokensAsync();
- userAddresses = await zeroEx.getAvailableAddressesAsync();
- addressWithETH = userAddresses[0];
- wethContractAddress = zeroEx.etherToken.getContractAddressIfExists() as string;
- depositWeiAmount = Web3Wrapper.toWei(new BigNumber(5));
- decimalPlaces = 7;
- addressWithoutFunds = userAddresses[1];
- });
- beforeEach(async () => {
- await blockchainLifecycle.startAsync();
- });
- afterEach(async () => {
- await blockchainLifecycle.revertAsync();
- });
- describe('#getContractAddressIfExists', async () => {
- it('should return contract address if connected to a known network', () => {
- const contractAddressIfExists = zeroEx.etherToken.getContractAddressIfExists();
- expect(contractAddressIfExists).to.not.be.undefined();
- });
- it('should throw if connected to a private network and contract addresses are not specified', () => {
- const UNKNOWN_NETWORK_NETWORK_ID = 10;
- expect(
- () =>
- new ZeroEx(provider, {
- networkId: UNKNOWN_NETWORK_NETWORK_ID,
- } as any),
- ).to.throw();
- });
- });
- describe('#depositAsync', () => {
- it('should successfully deposit ETH and issue Wrapped ETH tokens', async () => {
- const preETHBalance = await (zeroEx as any)._web3Wrapper.getBalanceInWeiAsync(addressWithETH);
- const preWETHBalance = await zeroEx.token.getBalanceAsync(wethContractAddress, addressWithETH);
- expect(preETHBalance).to.be.bignumber.gt(0);
- expect(preWETHBalance).to.be.bignumber.equal(0);
-
- const txHash = await zeroEx.etherToken.depositAsync(wethContractAddress, depositWeiAmount, addressWithETH);
- await zeroEx.awaitTransactionMinedAsync(txHash);
-
- const postETHBalanceInWei = await (zeroEx as any)._web3Wrapper.getBalanceInWeiAsync(addressWithETH);
- const postWETHBalanceInBaseUnits = await zeroEx.token.getBalanceAsync(wethContractAddress, addressWithETH);
-
- expect(postWETHBalanceInBaseUnits).to.be.bignumber.equal(depositWeiAmount);
- const remainingETHInWei = preETHBalance.minus(depositWeiAmount);
- const gasCost = remainingETHInWei.minus(postETHBalanceInWei);
- expect(gasCost).to.be.bignumber.lte(MAX_REASONABLE_GAS_COST_IN_WEI);
- });
- it('should throw if user has insufficient ETH balance for deposit', async () => {
- const preETHBalance = await (zeroEx as any)._web3Wrapper.getBalanceInWeiAsync(addressWithETH);
-
- const extraETHBalance = Web3Wrapper.toWei(new BigNumber(5));
- const overETHBalanceinWei = preETHBalance.add(extraETHBalance);
-
- return expect(
- zeroEx.etherToken.depositAsync(wethContractAddress, overETHBalanceinWei, addressWithETH),
- ).to.be.rejectedWith(ZeroExError.InsufficientEthBalanceForDeposit);
- });
- });
- describe('#withdrawAsync', () => {
- it('should successfully withdraw ETH in return for Wrapped ETH tokens', async () => {
- const ETHBalanceInWei = await (zeroEx as any)._web3Wrapper.getBalanceInWeiAsync(addressWithETH);
-
- await zeroEx.etherToken.depositAsync(wethContractAddress, depositWeiAmount, addressWithETH);
-
- const expectedPreETHBalance = ETHBalanceInWei.minus(depositWeiAmount);
- const preETHBalance = await (zeroEx as any)._web3Wrapper.getBalanceInWeiAsync(addressWithETH);
- const preWETHBalance = await zeroEx.token.getBalanceAsync(wethContractAddress, addressWithETH);
- let gasCost = expectedPreETHBalance.minus(preETHBalance);
- expect(gasCost).to.be.bignumber.lte(MAX_REASONABLE_GAS_COST_IN_WEI);
- expect(preWETHBalance).to.be.bignumber.equal(depositWeiAmount);
-
- const txHash = await zeroEx.etherToken.withdrawAsync(wethContractAddress, depositWeiAmount, addressWithETH);
- await zeroEx.awaitTransactionMinedAsync(txHash);
-
- const postETHBalance = await (zeroEx as any)._web3Wrapper.getBalanceInWeiAsync(addressWithETH);
- const postWETHBalanceInBaseUnits = await zeroEx.token.getBalanceAsync(wethContractAddress, addressWithETH);
-
- expect(postWETHBalanceInBaseUnits).to.be.bignumber.equal(0);
- const expectedETHBalance = preETHBalance.add(depositWeiAmount).round(decimalPlaces);
- gasCost = expectedETHBalance.minus(postETHBalance);
- expect(gasCost).to.be.bignumber.lte(MAX_REASONABLE_GAS_COST_IN_WEI);
- });
- it('should throw if user has insufficient WETH balance for withdrawal', async () => {
- const preWETHBalance = await zeroEx.token.getBalanceAsync(wethContractAddress, addressWithETH);
- expect(preWETHBalance).to.be.bignumber.equal(0);
-
- const overWETHBalance = preWETHBalance.add(999999999);
-
- return expect(
- zeroEx.etherToken.withdrawAsync(wethContractAddress, overWETHBalance, addressWithETH),
- ).to.be.rejectedWith(ZeroExError.InsufficientWEthBalanceForWithdrawal);
- });
- });
- describe('#subscribe', () => {
- const indexFilterValues = {};
- let etherTokenAddress: string;
- before(() => {
- const tokenUtils = new TokenUtils(tokens);
- const etherToken = tokenUtils.getWethTokenOrThrow();
- etherTokenAddress = etherToken.address;
- });
- afterEach(() => {
- zeroEx.etherToken.unsubscribeAll();
- });
- // Hack: Mocha does not allow a test to be both async and have a `done` callback
- // Since we need to await the receipt of the event in the `subscribe` callback,
- // we do need both. A hack is to make the top-level async fn w/ a done callback and then
- // wrap the rest of the test in an async block
- // Source: https://github.com/mochajs/mocha/issues/2407
- it('Should receive the Transfer event when tokens are transfered', (done: DoneCallback) => {
- (async () => {
- const callback = reportNodeCallbackErrors(done)(
- (logEvent: DecodedLogEvent<TransferContractEventArgs>) => {
- expect(logEvent).to.not.be.undefined();
- expect(logEvent.isRemoved).to.be.false();
- expect(logEvent.log.logIndex).to.be.equal(0);
- expect(logEvent.log.transactionIndex).to.be.equal(0);
- expect(logEvent.log.blockNumber).to.be.a('number');
- const args = logEvent.log.args;
- expect(args._from).to.be.equal(addressWithETH);
- expect(args._to).to.be.equal(addressWithoutFunds);
- expect(args._value).to.be.bignumber.equal(transferAmount);
- },
- );
- await zeroEx.etherToken.depositAsync(etherTokenAddress, transferAmount, addressWithETH);
- zeroEx.etherToken.subscribe(etherTokenAddress, EtherTokenEvents.Transfer, indexFilterValues, callback);
- await zeroEx.token.transferAsync(
- etherTokenAddress,
- addressWithETH,
- addressWithoutFunds,
- transferAmount,
- );
- })().catch(done);
- });
- it('Should receive the Approval event when allowance is being set', (done: DoneCallback) => {
- (async () => {
- const callback = reportNodeCallbackErrors(done)(
- (logEvent: DecodedLogEvent<ApprovalContractEventArgs>) => {
- expect(logEvent).to.not.be.undefined();
- expect(logEvent.isRemoved).to.be.false();
- const args = logEvent.log.args;
- expect(args._owner).to.be.equal(addressWithETH);
- expect(args._spender).to.be.equal(addressWithoutFunds);
- expect(args._value).to.be.bignumber.equal(allowanceAmount);
- },
- );
- zeroEx.etherToken.subscribe(etherTokenAddress, EtherTokenEvents.Approval, indexFilterValues, callback);
- await zeroEx.token.setAllowanceAsync(
- etherTokenAddress,
- addressWithETH,
- addressWithoutFunds,
- allowanceAmount,
- );
- })().catch(done);
- });
- it('Should receive the Deposit event when ether is being deposited', (done: DoneCallback) => {
- (async () => {
- const callback = reportNodeCallbackErrors(done)(
- (logEvent: DecodedLogEvent<DepositContractEventArgs>) => {
- expect(logEvent).to.not.be.undefined();
- expect(logEvent.isRemoved).to.be.false();
- const args = logEvent.log.args;
- expect(args._owner).to.be.equal(addressWithETH);
- expect(args._value).to.be.bignumber.equal(depositAmount);
- },
- );
- zeroEx.etherToken.subscribe(etherTokenAddress, EtherTokenEvents.Deposit, indexFilterValues, callback);
- await zeroEx.etherToken.depositAsync(etherTokenAddress, depositAmount, addressWithETH);
- })().catch(done);
- });
- it('Should receive the Withdrawal event when ether is being withdrawn', (done: DoneCallback) => {
- (async () => {
- const callback = reportNodeCallbackErrors(done)(
- (logEvent: DecodedLogEvent<WithdrawalContractEventArgs>) => {
- expect(logEvent).to.not.be.undefined();
- expect(logEvent.isRemoved).to.be.false();
- const args = logEvent.log.args;
- expect(args._owner).to.be.equal(addressWithETH);
- expect(args._value).to.be.bignumber.equal(depositAmount);
- },
- );
- await zeroEx.etherToken.depositAsync(etherTokenAddress, depositAmount, addressWithETH);
- zeroEx.etherToken.subscribe(
- etherTokenAddress,
- EtherTokenEvents.Withdrawal,
- indexFilterValues,
- callback,
- );
- await zeroEx.etherToken.withdrawAsync(etherTokenAddress, withdrawalAmount, addressWithETH);
- })().catch(done);
- });
- it('should cancel outstanding subscriptions when ZeroEx.setProvider is called', (done: DoneCallback) => {
- (async () => {
- const callbackNeverToBeCalled = reportNodeCallbackErrors(done)(
- (logEvent: DecodedLogEvent<ApprovalContractEventArgs>) => {
- done(new Error('Expected this subscription to have been cancelled'));
- },
- );
- zeroEx.etherToken.subscribe(
- etherTokenAddress,
- EtherTokenEvents.Transfer,
- indexFilterValues,
- callbackNeverToBeCalled,
- );
- const callbackToBeCalled = reportNodeCallbackErrors(done)();
- zeroEx.setProvider(provider, constants.TESTRPC_NETWORK_ID);
- await zeroEx.etherToken.depositAsync(etherTokenAddress, transferAmount, addressWithETH);
- zeroEx.etherToken.subscribe(
- etherTokenAddress,
- EtherTokenEvents.Transfer,
- indexFilterValues,
- callbackToBeCalled,
- );
- await zeroEx.token.transferAsync(
- etherTokenAddress,
- addressWithETH,
- addressWithoutFunds,
- transferAmount,
- );
- })().catch(done);
- });
- it('Should cancel subscription when unsubscribe called', (done: DoneCallback) => {
- (async () => {
- const callbackNeverToBeCalled = reportNodeCallbackErrors(done)(
- (logEvent: DecodedLogEvent<ApprovalContractEventArgs>) => {
- done(new Error('Expected this subscription to have been cancelled'));
- },
- );
- await zeroEx.etherToken.depositAsync(etherTokenAddress, transferAmount, addressWithETH);
- const subscriptionToken = zeroEx.etherToken.subscribe(
- etherTokenAddress,
- EtherTokenEvents.Transfer,
- indexFilterValues,
- callbackNeverToBeCalled,
- );
- zeroEx.etherToken.unsubscribe(subscriptionToken);
- await zeroEx.token.transferAsync(
- etherTokenAddress,
- addressWithETH,
- addressWithoutFunds,
- transferAmount,
- );
- done();
- })().catch(done);
- });
- });
- describe('#getLogsAsync', () => {
- let etherTokenAddress: string;
- let tokenTransferProxyAddress: string;
- const blockRange: BlockRange = {
- fromBlock: 0,
- toBlock: BlockParamLiteral.Latest,
- };
- let txHash: string;
- before(() => {
- addressWithETH = userAddresses[0];
- const tokenUtils = new TokenUtils(tokens);
- const etherToken = tokenUtils.getWethTokenOrThrow();
- etherTokenAddress = etherToken.address;
- tokenTransferProxyAddress = zeroEx.proxy.getContractAddress();
- });
- it('should get logs with decoded args emitted by Approval', async () => {
- txHash = await zeroEx.token.setUnlimitedProxyAllowanceAsync(etherTokenAddress, addressWithETH);
- await zeroEx.awaitTransactionMinedAsync(txHash);
- const eventName = EtherTokenEvents.Approval;
- const indexFilterValues = {};
- const logs = await zeroEx.etherToken.getLogsAsync<ApprovalContractEventArgs>(
- etherTokenAddress,
- eventName,
- blockRange,
- indexFilterValues,
- );
- expect(logs).to.have.length(1);
- const args = logs[0].args;
- expect(logs[0].event).to.be.equal(eventName);
- expect(args._owner).to.be.equal(addressWithETH);
- expect(args._spender).to.be.equal(tokenTransferProxyAddress);
- expect(args._value).to.be.bignumber.equal(zeroEx.token.UNLIMITED_ALLOWANCE_IN_BASE_UNITS);
- });
- it('should get logs with decoded args emitted by Deposit', async () => {
- await zeroEx.etherToken.depositAsync(etherTokenAddress, depositAmount, addressWithETH);
- const eventName = EtherTokenEvents.Deposit;
- const indexFilterValues = {};
- const logs = await zeroEx.etherToken.getLogsAsync<DepositContractEventArgs>(
- etherTokenAddress,
- eventName,
- blockRange,
- indexFilterValues,
- );
- expect(logs).to.have.length(1);
- const args = logs[0].args;
- expect(logs[0].event).to.be.equal(eventName);
- expect(args._owner).to.be.equal(addressWithETH);
- expect(args._value).to.be.bignumber.equal(depositAmount);
- });
- it('should only get the logs with the correct event name', async () => {
- txHash = await zeroEx.token.setUnlimitedProxyAllowanceAsync(etherTokenAddress, addressWithETH);
- await zeroEx.awaitTransactionMinedAsync(txHash);
- const differentEventName = EtherTokenEvents.Transfer;
- const indexFilterValues = {};
- const logs = await zeroEx.etherToken.getLogsAsync(
- etherTokenAddress,
- differentEventName,
- blockRange,
- indexFilterValues,
- );
- expect(logs).to.have.length(0);
- });
- it('should only get the logs with the correct indexed fields', async () => {
- txHash = await zeroEx.token.setUnlimitedProxyAllowanceAsync(etherTokenAddress, addressWithETH);
- await zeroEx.awaitTransactionMinedAsync(txHash);
- txHash = await zeroEx.token.setUnlimitedProxyAllowanceAsync(etherTokenAddress, addressWithoutFunds);
- await zeroEx.awaitTransactionMinedAsync(txHash);
- const eventName = EtherTokenEvents.Approval;
- const indexFilterValues = {
- _owner: addressWithETH,
- };
- const logs = await zeroEx.etherToken.getLogsAsync<ApprovalContractEventArgs>(
- etherTokenAddress,
- eventName,
- blockRange,
- indexFilterValues,
- );
- expect(logs).to.have.length(1);
- const args = logs[0].args;
- expect(args._owner).to.be.equal(addressWithETH);
- });
- });
-});
diff --git a/packages/0x.js/test/event_watcher_test.ts b/packages/0x.js/test/event_watcher_test.ts
deleted file mode 100644
index 40ffcc2f6..000000000
--- a/packages/0x.js/test/event_watcher_test.ts
+++ /dev/null
@@ -1,125 +0,0 @@
-import { web3Factory } from '@0xproject/dev-utils';
-import { LogEntry } from '@0xproject/types';
-import { Web3Wrapper } from '@0xproject/web3-wrapper';
-import * as chai from 'chai';
-import * as _ from 'lodash';
-import 'mocha';
-import * as Sinon from 'sinon';
-
-import { LogEvent } from '../src';
-import { EventWatcher } from '../src/order_watcher/event_watcher';
-import { DoneCallback } from '../src/types';
-
-import { chaiSetup } from './utils/chai_setup';
-import { reportNodeCallbackErrors } from './utils/report_callback_errors';
-import { provider } from './utils/web3_wrapper';
-
-chaiSetup.configure();
-const expect = chai.expect;
-
-describe('EventWatcher', () => {
- let stubs: Sinon.SinonStub[] = [];
- let eventWatcher: EventWatcher;
- let web3Wrapper: Web3Wrapper;
- const logA: LogEntry = {
- address: '0x71d271f8b14adef568f8f28f1587ce7271ac4ca5',
- blockHash: null,
- blockNumber: null,
- data: '',
- logIndex: null,
- topics: [],
- transactionHash: '0x004881d38cd4a8f72f1a0d68c8b9b8124504706041ff37019c1d1ed6bfda8e17',
- transactionIndex: 0,
- };
- const logB: LogEntry = {
- address: '0x8d12a197cb00d4747a1fe03395095ce2a5cc6819',
- blockHash: null,
- blockNumber: null,
- data: '',
- logIndex: null,
- topics: ['0xf341246adaac6f497bc2a656f546ab9e182111d630394f0c57c710a59a2cb567'],
- transactionHash: '0x01ef3c048b18d9b09ea195b4ed94cf8dd5f3d857a1905ff886b152cfb1166f25',
- transactionIndex: 0,
- };
- const logC: LogEntry = {
- address: '0x1d271f8b174adef58f1587ce68f8f27271ac4ca5',
- blockHash: null,
- blockNumber: null,
- data: '',
- logIndex: null,
- topics: ['0xf341246adaac6f497bc2a656f546ab9e182111d630394f0c57c710a59a2cb567'],
- transactionHash: '0x01ef3c048b18d9b09ea195b4ed94cf8dd5f3d857a1905ff886b152cfb1166f25',
- transactionIndex: 0,
- };
- before(async () => {
- const pollingIntervalMs = 10;
- web3Wrapper = new Web3Wrapper(provider);
- eventWatcher = new EventWatcher(web3Wrapper, pollingIntervalMs);
- });
- afterEach(() => {
- // clean up any stubs after the test has completed
- _.each(stubs, s => s.restore());
- stubs = [];
- eventWatcher.unsubscribe();
- });
- it('correctly emits initial log events', (done: DoneCallback) => {
- const logs: LogEntry[] = [logA, logB];
- const expectedLogEvents = [
- {
- removed: false,
- ...logA,
- },
- {
- removed: false,
- ...logB,
- },
- ];
- const getLogsStub = Sinon.stub(web3Wrapper, 'getLogsAsync');
- getLogsStub.onCall(0).returns(logs);
- stubs.push(getLogsStub);
- const expectedToBeCalledOnce = false;
- const callback = reportNodeCallbackErrors(done, expectedToBeCalledOnce)((event: LogEvent) => {
- const expectedLogEvent = expectedLogEvents.shift();
- expect(event).to.be.deep.equal(expectedLogEvent);
- if (_.isEmpty(expectedLogEvents)) {
- done();
- }
- });
- eventWatcher.subscribe(callback);
- });
- it('correctly computes the difference and emits only changes', (done: DoneCallback) => {
- const initialLogs: LogEntry[] = [logA, logB];
- const changedLogs: LogEntry[] = [logA, logC];
- const expectedLogEvents = [
- {
- removed: false,
- ...logA,
- },
- {
- removed: false,
- ...logB,
- },
- {
- removed: true,
- ...logB,
- },
- {
- removed: false,
- ...logC,
- },
- ];
- const getLogsStub = Sinon.stub(web3Wrapper, 'getLogsAsync');
- getLogsStub.onCall(0).returns(initialLogs);
- getLogsStub.onCall(1).returns(changedLogs);
- stubs.push(getLogsStub);
- const expectedToBeCalledOnce = false;
- const callback = reportNodeCallbackErrors(done, expectedToBeCalledOnce)((event: LogEvent) => {
- const expectedLogEvent = expectedLogEvents.shift();
- expect(event).to.be.deep.equal(expectedLogEvent);
- if (_.isEmpty(expectedLogEvents)) {
- done();
- }
- });
- eventWatcher.subscribe(callback);
- });
-});
diff --git a/packages/0x.js/test/exchange_transfer_simulator_test.ts b/packages/0x.js/test/exchange_transfer_simulator_test.ts
deleted file mode 100644
index cb976a0ae..000000000
--- a/packages/0x.js/test/exchange_transfer_simulator_test.ts
+++ /dev/null
@@ -1,117 +0,0 @@
-import { BlockchainLifecycle, devConstants } from '@0xproject/dev-utils';
-import { BlockParamLiteral } from '@0xproject/types';
-import { BigNumber } from '@0xproject/utils';
-import * as chai from 'chai';
-
-import { ExchangeContractErrs, Token, ZeroEx } from '../src';
-import { TradeSide, TransferType } from '../src/types';
-import { ExchangeTransferSimulator } from '../src/utils/exchange_transfer_simulator';
-
-import { chaiSetup } from './utils/chai_setup';
-import { constants } from './utils/constants';
-import { provider, web3Wrapper } from './utils/web3_wrapper';
-
-chaiSetup.configure();
-const expect = chai.expect;
-const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
-
-describe('ExchangeTransferSimulator', () => {
- const config = {
- networkId: constants.TESTRPC_NETWORK_ID,
- };
- const zeroEx = new ZeroEx(provider, config);
- const transferAmount = new BigNumber(5);
- let userAddresses: string[];
- let tokens: Token[];
- let coinbase: string;
- let sender: string;
- let recipient: string;
- let exampleTokenAddress: string;
- let exchangeTransferSimulator: ExchangeTransferSimulator;
- let txHash: string;
- before(async () => {
- userAddresses = await zeroEx.getAvailableAddressesAsync();
- [coinbase, sender, recipient] = userAddresses;
- tokens = await zeroEx.tokenRegistry.getTokensAsync();
- exampleTokenAddress = tokens[0].address;
- });
- beforeEach(async () => {
- await blockchainLifecycle.startAsync();
- });
- afterEach(async () => {
- await blockchainLifecycle.revertAsync();
- });
- describe('#transferFromAsync', () => {
- beforeEach(() => {
- exchangeTransferSimulator = new ExchangeTransferSimulator(zeroEx.token, BlockParamLiteral.Latest);
- });
- it("throws if the user doesn't have enough allowance", async () => {
- return expect(
- exchangeTransferSimulator.transferFromAsync(
- exampleTokenAddress,
- sender,
- recipient,
- transferAmount,
- TradeSide.Taker,
- TransferType.Trade,
- ),
- ).to.be.rejectedWith(ExchangeContractErrs.InsufficientTakerAllowance);
- });
- it("throws if the user doesn't have enough balance", async () => {
- txHash = await zeroEx.token.setProxyAllowanceAsync(exampleTokenAddress, sender, transferAmount);
- await zeroEx.awaitTransactionMinedAsync(txHash);
- return expect(
- exchangeTransferSimulator.transferFromAsync(
- exampleTokenAddress,
- sender,
- recipient,
- transferAmount,
- TradeSide.Maker,
- TransferType.Trade,
- ),
- ).to.be.rejectedWith(ExchangeContractErrs.InsufficientMakerBalance);
- });
- it('updates balances and proxyAllowance after transfer', async () => {
- txHash = await zeroEx.token.transferAsync(exampleTokenAddress, coinbase, sender, transferAmount);
- await zeroEx.awaitTransactionMinedAsync(txHash);
- txHash = await zeroEx.token.setProxyAllowanceAsync(exampleTokenAddress, sender, transferAmount);
- await zeroEx.awaitTransactionMinedAsync(txHash);
- await exchangeTransferSimulator.transferFromAsync(
- exampleTokenAddress,
- sender,
- recipient,
- transferAmount,
- TradeSide.Taker,
- TransferType.Trade,
- );
- const store = (exchangeTransferSimulator as any)._store;
- const senderBalance = await store.getBalanceAsync(exampleTokenAddress, sender);
- const recipientBalance = await store.getBalanceAsync(exampleTokenAddress, recipient);
- const senderProxyAllowance = await store.getProxyAllowanceAsync(exampleTokenAddress, sender);
- expect(senderBalance).to.be.bignumber.equal(0);
- expect(recipientBalance).to.be.bignumber.equal(transferAmount);
- expect(senderProxyAllowance).to.be.bignumber.equal(0);
- });
- it("doesn't update proxyAllowance after transfer if unlimited", async () => {
- txHash = await zeroEx.token.transferAsync(exampleTokenAddress, coinbase, sender, transferAmount);
- await zeroEx.awaitTransactionMinedAsync(txHash);
- txHash = await zeroEx.token.setUnlimitedProxyAllowanceAsync(exampleTokenAddress, sender);
- await zeroEx.awaitTransactionMinedAsync(txHash);
- await exchangeTransferSimulator.transferFromAsync(
- exampleTokenAddress,
- sender,
- recipient,
- transferAmount,
- TradeSide.Taker,
- TransferType.Trade,
- );
- const store = (exchangeTransferSimulator as any)._store;
- const senderBalance = await store.getBalanceAsync(exampleTokenAddress, sender);
- const recipientBalance = await store.getBalanceAsync(exampleTokenAddress, recipient);
- const senderProxyAllowance = await store.getProxyAllowanceAsync(exampleTokenAddress, sender);
- expect(senderBalance).to.be.bignumber.equal(0);
- expect(recipientBalance).to.be.bignumber.equal(transferAmount);
- expect(senderProxyAllowance).to.be.bignumber.equal(zeroEx.token.UNLIMITED_ALLOWANCE_IN_BASE_UNITS);
- });
- });
-});
diff --git a/packages/0x.js/test/exchange_wrapper_test.ts b/packages/0x.js/test/exchange_wrapper_test.ts
deleted file mode 100644
index 65f4e8251..000000000
--- a/packages/0x.js/test/exchange_wrapper_test.ts
+++ /dev/null
@@ -1,1195 +0,0 @@
-import { BlockchainLifecycle, devConstants, web3Factory } from '@0xproject/dev-utils';
-import { BlockParamLiteral } from '@0xproject/types';
-import { BigNumber } from '@0xproject/utils';
-import * as chai from 'chai';
-import * as _ from 'lodash';
-import 'mocha';
-
-import {
- BlockRange,
- DecodedLogEvent,
- ExchangeContractErrs,
- ExchangeEvents,
- LogCancelContractEventArgs,
- LogFillContractEventArgs,
- OrderCancellationRequest,
- OrderFillRequest,
- OrderState,
- SignedOrder,
- Token,
- ZeroEx,
-} from '../src';
-import { DoneCallback } from '../src/types';
-
-import { chaiSetup } from './utils/chai_setup';
-import { constants } from './utils/constants';
-import { FillScenarios } from './utils/fill_scenarios';
-import { reportNodeCallbackErrors } from './utils/report_callback_errors';
-import { TokenUtils } from './utils/token_utils';
-import { provider, web3Wrapper } from './utils/web3_wrapper';
-
-chaiSetup.configure();
-const expect = chai.expect;
-const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
-
-const NON_EXISTENT_ORDER_HASH = '0x79370342234e7acd6bbeac335bd3bb1d368383294b64b8160a00f4060e4d3777';
-
-describe('ExchangeWrapper', () => {
- let zeroEx: ZeroEx;
- let tokenUtils: TokenUtils;
- let tokens: Token[];
- let userAddresses: string[];
- let zrxTokenAddress: string;
- let fillScenarios: FillScenarios;
- let exchangeContractAddress: string;
- const config = {
- networkId: constants.TESTRPC_NETWORK_ID,
- };
- before(async () => {
- zeroEx = new ZeroEx(provider, config);
- exchangeContractAddress = zeroEx.exchange.getContractAddress();
- userAddresses = await zeroEx.getAvailableAddressesAsync();
- tokens = await zeroEx.tokenRegistry.getTokensAsync();
- tokenUtils = new TokenUtils(tokens);
- zrxTokenAddress = tokenUtils.getProtocolTokenOrThrow().address;
- fillScenarios = new FillScenarios(zeroEx, userAddresses, tokens, zrxTokenAddress, exchangeContractAddress);
- await fillScenarios.initTokenBalancesAsync();
- });
- beforeEach(async () => {
- await blockchainLifecycle.startAsync();
- });
- afterEach(async () => {
- await blockchainLifecycle.revertAsync();
- });
- describe('fillOrKill order(s)', () => {
- let makerTokenAddress: string;
- let takerTokenAddress: string;
- let coinbase: string;
- let makerAddress: string;
- let takerAddress: string;
- let feeRecipient: string;
- const takerTokenFillAmount = new BigNumber(5);
- before(async () => {
- [coinbase, makerAddress, takerAddress, feeRecipient] = userAddresses;
- tokens = await zeroEx.tokenRegistry.getTokensAsync();
- const [makerToken, takerToken] = tokenUtils.getDummyTokens();
- makerTokenAddress = makerToken.address;
- takerTokenAddress = takerToken.address;
- });
- describe('#batchFillOrKillAsync', () => {
- it('successfully batch fillOrKill', async () => {
- const fillableAmount = new BigNumber(5);
- const partialFillTakerAmount = new BigNumber(2);
- const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
- makerTokenAddress,
- takerTokenAddress,
- makerAddress,
- takerAddress,
- fillableAmount,
- );
- const anotherSignedOrder = await fillScenarios.createFillableSignedOrderAsync(
- makerTokenAddress,
- takerTokenAddress,
- makerAddress,
- takerAddress,
- fillableAmount,
- );
- const orderFillRequests = [
- {
- signedOrder,
- takerTokenFillAmount: partialFillTakerAmount,
- },
- {
- signedOrder: anotherSignedOrder,
- takerTokenFillAmount: partialFillTakerAmount,
- },
- ];
- await zeroEx.exchange.batchFillOrKillAsync(orderFillRequests, takerAddress);
- });
- describe('order transaction options', () => {
- let signedOrder: SignedOrder;
- let orderFillRequests: OrderFillRequest[];
- const fillableAmount = new BigNumber(5);
- beforeEach(async () => {
- signedOrder = await fillScenarios.createFillableSignedOrderAsync(
- makerTokenAddress,
- takerTokenAddress,
- makerAddress,
- takerAddress,
- fillableAmount,
- );
- orderFillRequests = [
- {
- signedOrder,
- takerTokenFillAmount: new BigNumber(0),
- },
- ];
- });
- it('should validate when orderTransactionOptions are not present', async () => {
- return expect(
- zeroEx.exchange.batchFillOrKillAsync(orderFillRequests, takerAddress),
- ).to.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero);
- });
- it('should validate when orderTransactionOptions specify to validate', async () => {
- return expect(
- zeroEx.exchange.batchFillOrKillAsync(orderFillRequests, takerAddress, {
- shouldValidate: true,
- }),
- ).to.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero);
- });
- it('should not validate when orderTransactionOptions specify not to validate', async () => {
- return expect(
- zeroEx.exchange.batchFillOrKillAsync(orderFillRequests, takerAddress, {
- shouldValidate: false,
- }),
- ).to.not.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero);
- });
- });
- });
- describe('#fillOrKillOrderAsync', () => {
- let signedOrder: SignedOrder;
- const fillableAmount = new BigNumber(5);
- beforeEach(async () => {
- signedOrder = await fillScenarios.createFillableSignedOrderAsync(
- makerTokenAddress,
- takerTokenAddress,
- makerAddress,
- takerAddress,
- fillableAmount,
- );
- });
- describe('successful fills', () => {
- it('should fill a valid order', async () => {
- 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,
- );
- await zeroEx.exchange.fillOrKillOrderAsync(signedOrder, takerTokenFillAmount, takerAddress);
- expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, makerAddress)).to.be.bignumber.equal(
- fillableAmount.minus(takerTokenFillAmount),
- );
- expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, makerAddress)).to.be.bignumber.equal(
- takerTokenFillAmount,
- );
- expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, takerAddress)).to.be.bignumber.equal(
- takerTokenFillAmount,
- );
- expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, takerAddress)).to.be.bignumber.equal(
- fillableAmount.minus(takerTokenFillAmount),
- );
- });
- it('should partially fill a valid order', async () => {
- const partialFillAmount = new BigNumber(3);
- await zeroEx.exchange.fillOrKillOrderAsync(signedOrder, partialFillAmount, takerAddress);
- expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, makerAddress)).to.be.bignumber.equal(
- fillableAmount.minus(partialFillAmount),
- );
- expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, makerAddress)).to.be.bignumber.equal(
- partialFillAmount,
- );
- expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, takerAddress)).to.be.bignumber.equal(
- partialFillAmount,
- );
- expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, takerAddress)).to.be.bignumber.equal(
- fillableAmount.minus(partialFillAmount),
- );
- });
- });
- describe('order transaction options', () => {
- const emptyFillableAmount = new BigNumber(0);
- it('should validate when orderTransactionOptions are not present', async () => {
- return expect(
- zeroEx.exchange.fillOrKillOrderAsync(signedOrder, emptyFillableAmount, takerAddress),
- ).to.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero);
- });
- it('should validate when orderTransactionOptions specify to validate', async () => {
- return expect(
- zeroEx.exchange.fillOrKillOrderAsync(signedOrder, emptyFillableAmount, takerAddress, {
- shouldValidate: true,
- }),
- ).to.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero);
- });
- it('should not validate when orderTransactionOptions specify not to validate', async () => {
- return expect(
- zeroEx.exchange.fillOrKillOrderAsync(signedOrder, emptyFillableAmount, takerAddress, {
- shouldValidate: false,
- }),
- ).to.not.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero);
- });
- });
- });
- });
- describe('fill order(s)', () => {
- let makerTokenAddress: string;
- let takerTokenAddress: string;
- let coinbase: string;
- let makerAddress: string;
- let takerAddress: string;
- let feeRecipient: string;
- const fillableAmount = new BigNumber(5);
- const takerTokenFillAmount = new BigNumber(5);
- const shouldThrowOnInsufficientBalanceOrAllowance = true;
- before(async () => {
- [coinbase, makerAddress, takerAddress, feeRecipient] = userAddresses;
- tokens = await zeroEx.tokenRegistry.getTokensAsync();
- const [makerToken, takerToken] = tokenUtils.getDummyTokens();
- makerTokenAddress = makerToken.address;
- takerTokenAddress = takerToken.address;
- });
- describe('#fillOrderAsync', () => {
- describe('successful fills', () => {
- it('should fill a valid order', async () => {
- const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
- 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,
- );
- const txHash = await zeroEx.exchange.fillOrderAsync(
- signedOrder,
- takerTokenFillAmount,
- shouldThrowOnInsufficientBalanceOrAllowance,
- takerAddress,
- );
- await zeroEx.awaitTransactionMinedAsync(txHash);
- expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, makerAddress)).to.be.bignumber.equal(
- fillableAmount.minus(takerTokenFillAmount),
- );
- expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, makerAddress)).to.be.bignumber.equal(
- takerTokenFillAmount,
- );
- expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, takerAddress)).to.be.bignumber.equal(
- takerTokenFillAmount,
- );
- expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, takerAddress)).to.be.bignumber.equal(
- fillableAmount.minus(takerTokenFillAmount),
- );
- });
- it('should partially fill the valid order', async () => {
- const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
- makerTokenAddress,
- takerTokenAddress,
- makerAddress,
- takerAddress,
- fillableAmount,
- );
- const partialFillAmount = new BigNumber(3);
- const txHash = await zeroEx.exchange.fillOrderAsync(
- signedOrder,
- partialFillAmount,
- shouldThrowOnInsufficientBalanceOrAllowance,
- takerAddress,
- );
- await zeroEx.awaitTransactionMinedAsync(txHash);
- expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, makerAddress)).to.be.bignumber.equal(
- fillableAmount.minus(partialFillAmount),
- );
- expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, makerAddress)).to.be.bignumber.equal(
- partialFillAmount,
- );
- expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, takerAddress)).to.be.bignumber.equal(
- partialFillAmount,
- );
- expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, takerAddress)).to.be.bignumber.equal(
- fillableAmount.minus(partialFillAmount),
- );
- });
- it('should fill the valid orders with fees', async () => {
- const makerFee = new BigNumber(1);
- const takerFee = new BigNumber(2);
- const signedOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync(
- makerTokenAddress,
- takerTokenAddress,
- makerFee,
- takerFee,
- makerAddress,
- takerAddress,
- fillableAmount,
- feeRecipient,
- );
- const txHash = await zeroEx.exchange.fillOrderAsync(
- signedOrder,
- takerTokenFillAmount,
- shouldThrowOnInsufficientBalanceOrAllowance,
- takerAddress,
- );
- await zeroEx.awaitTransactionMinedAsync(txHash);
- expect(await zeroEx.token.getBalanceAsync(zrxTokenAddress, feeRecipient)).to.be.bignumber.equal(
- makerFee.plus(takerFee),
- );
- });
- });
- describe('order transaction options', () => {
- let signedOrder: SignedOrder;
- const emptyFillTakerAmount = new BigNumber(0);
- beforeEach(async () => {
- signedOrder = await fillScenarios.createFillableSignedOrderAsync(
- makerTokenAddress,
- takerTokenAddress,
- makerAddress,
- takerAddress,
- fillableAmount,
- );
- });
- it('should validate when orderTransactionOptions are not present', async () => {
- return expect(
- zeroEx.exchange.fillOrderAsync(
- signedOrder,
- emptyFillTakerAmount,
- shouldThrowOnInsufficientBalanceOrAllowance,
- takerAddress,
- ),
- ).to.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero);
- });
- it('should validate when orderTransactionOptions specify to validate', async () => {
- return expect(
- zeroEx.exchange.fillOrderAsync(
- signedOrder,
- emptyFillTakerAmount,
- shouldThrowOnInsufficientBalanceOrAllowance,
- takerAddress,
- {
- shouldValidate: true,
- },
- ),
- ).to.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero);
- });
- it('should not validate when orderTransactionOptions specify not to validate', async () => {
- return expect(
- zeroEx.exchange.fillOrderAsync(
- signedOrder,
- emptyFillTakerAmount,
- shouldThrowOnInsufficientBalanceOrAllowance,
- takerAddress,
- {
- shouldValidate: false,
- },
- ),
- ).to.not.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero);
- });
- });
- describe('negative fill amount', async () => {
- let signedOrder: SignedOrder;
- const negativeFillTakerAmount = new BigNumber(-100);
- beforeEach(async () => {
- signedOrder = await fillScenarios.createFillableSignedOrderAsync(
- makerTokenAddress,
- takerTokenAddress,
- makerAddress,
- takerAddress,
- fillableAmount,
- );
- });
- it('should not allow the exchange wrapper to fill if amount is negative', async () => {
- return expect(
- zeroEx.exchange.fillOrderAsync(
- signedOrder,
- negativeFillTakerAmount,
- shouldThrowOnInsufficientBalanceOrAllowance,
- takerAddress,
- ),
- ).to.be.rejected();
- });
- });
- });
- describe('#batchFillOrdersAsync', () => {
- let signedOrder: SignedOrder;
- let signedOrderHashHex: string;
- let anotherSignedOrder: SignedOrder;
- let anotherOrderHashHex: string;
- let orderFillBatch: OrderFillRequest[];
- beforeEach(async () => {
- signedOrder = await fillScenarios.createFillableSignedOrderAsync(
- makerTokenAddress,
- takerTokenAddress,
- makerAddress,
- takerAddress,
- fillableAmount,
- );
- signedOrderHashHex = ZeroEx.getOrderHashHex(signedOrder);
- anotherSignedOrder = await fillScenarios.createFillableSignedOrderAsync(
- makerTokenAddress,
- takerTokenAddress,
- makerAddress,
- takerAddress,
- fillableAmount,
- );
- anotherOrderHashHex = ZeroEx.getOrderHashHex(anotherSignedOrder);
- });
- describe('successful batch fills', () => {
- beforeEach(() => {
- orderFillBatch = [
- {
- signedOrder,
- takerTokenFillAmount,
- },
- {
- signedOrder: anotherSignedOrder,
- takerTokenFillAmount,
- },
- ];
- });
- it('should throw if a batch is empty', async () => {
- return expect(
- zeroEx.exchange.batchFillOrdersAsync(
- [],
- shouldThrowOnInsufficientBalanceOrAllowance,
- takerAddress,
- ),
- ).to.be.rejectedWith(ExchangeContractErrs.BatchOrdersMustHaveAtLeastOneItem);
- });
- it('should successfully fill multiple orders', async () => {
- const txHash = await zeroEx.exchange.batchFillOrdersAsync(
- orderFillBatch,
- shouldThrowOnInsufficientBalanceOrAllowance,
- takerAddress,
- );
- await zeroEx.awaitTransactionMinedAsync(txHash);
- const filledAmount = await zeroEx.exchange.getFilledTakerAmountAsync(signedOrderHashHex);
- const anotherFilledAmount = await zeroEx.exchange.getFilledTakerAmountAsync(anotherOrderHashHex);
- expect(filledAmount).to.be.bignumber.equal(takerTokenFillAmount);
- expect(anotherFilledAmount).to.be.bignumber.equal(takerTokenFillAmount);
- });
- });
- describe('order transaction options', () => {
- beforeEach(async () => {
- const emptyFillTakerAmount = new BigNumber(0);
- orderFillBatch = [
- {
- signedOrder,
- takerTokenFillAmount: emptyFillTakerAmount,
- },
- {
- signedOrder: anotherSignedOrder,
- takerTokenFillAmount: emptyFillTakerAmount,
- },
- ];
- });
- it('should validate when orderTransactionOptions are not present', async () => {
- return expect(
- zeroEx.exchange.batchFillOrdersAsync(
- orderFillBatch,
- shouldThrowOnInsufficientBalanceOrAllowance,
- takerAddress,
- ),
- ).to.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero);
- });
- it('should validate when orderTransactionOptions specify to validate', async () => {
- return expect(
- zeroEx.exchange.batchFillOrdersAsync(
- orderFillBatch,
- shouldThrowOnInsufficientBalanceOrAllowance,
- takerAddress,
- {
- shouldValidate: true,
- },
- ),
- ).to.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero);
- });
- it('should not validate when orderTransactionOptions specify not to validate', async () => {
- return expect(
- zeroEx.exchange.batchFillOrdersAsync(
- orderFillBatch,
- shouldThrowOnInsufficientBalanceOrAllowance,
- takerAddress,
- {
- shouldValidate: false,
- },
- ),
- ).to.not.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero);
- });
- });
- describe('negative batch fill amount', async () => {
- beforeEach(async () => {
- const negativeFillTakerAmount = new BigNumber(-100);
- orderFillBatch = [
- {
- signedOrder,
- takerTokenFillAmount,
- },
- {
- signedOrder: anotherSignedOrder,
- takerTokenFillAmount: negativeFillTakerAmount,
- },
- ];
- });
- it('should not allow the exchange wrapper to batch fill if any amount is negative', async () => {
- return expect(
- zeroEx.exchange.batchFillOrdersAsync(
- orderFillBatch,
- shouldThrowOnInsufficientBalanceOrAllowance,
- takerAddress,
- ),
- ).to.be.rejected();
- });
- });
- });
- describe('#fillOrdersUpTo', () => {
- let signedOrder: SignedOrder;
- let signedOrderHashHex: string;
- let anotherSignedOrder: SignedOrder;
- let anotherOrderHashHex: string;
- let signedOrders: SignedOrder[];
- const fillUpToAmount = fillableAmount.plus(fillableAmount).minus(1);
- beforeEach(async () => {
- signedOrder = await fillScenarios.createFillableSignedOrderAsync(
- makerTokenAddress,
- takerTokenAddress,
- makerAddress,
- takerAddress,
- fillableAmount,
- );
- signedOrderHashHex = ZeroEx.getOrderHashHex(signedOrder);
- anotherSignedOrder = await fillScenarios.createFillableSignedOrderAsync(
- makerTokenAddress,
- takerTokenAddress,
- makerAddress,
- takerAddress,
- fillableAmount,
- );
- anotherOrderHashHex = ZeroEx.getOrderHashHex(anotherSignedOrder);
- signedOrders = [signedOrder, anotherSignedOrder];
- });
- describe('successful batch fills', () => {
- it('should throw if a batch is empty', async () => {
- return expect(
- zeroEx.exchange.fillOrdersUpToAsync(
- [],
- fillUpToAmount,
- shouldThrowOnInsufficientBalanceOrAllowance,
- takerAddress,
- ),
- ).to.be.rejectedWith(ExchangeContractErrs.BatchOrdersMustHaveAtLeastOneItem);
- });
- it('should successfully fill up to specified amount when all orders are fully funded', async () => {
- const txHash = await zeroEx.exchange.fillOrdersUpToAsync(
- signedOrders,
- fillUpToAmount,
- shouldThrowOnInsufficientBalanceOrAllowance,
- takerAddress,
- );
- await zeroEx.awaitTransactionMinedAsync(txHash);
- const filledAmount = await zeroEx.exchange.getFilledTakerAmountAsync(signedOrderHashHex);
- const anotherFilledAmount = await zeroEx.exchange.getFilledTakerAmountAsync(anotherOrderHashHex);
- expect(filledAmount).to.be.bignumber.equal(fillableAmount);
- const remainingFillAmount = fillableAmount.minus(1);
- expect(anotherFilledAmount).to.be.bignumber.equal(remainingFillAmount);
- });
- it('should successfully fill up to specified amount and leave the rest of the orders untouched', async () => {
- const txHash = await zeroEx.exchange.fillOrdersUpToAsync(
- signedOrders,
- fillableAmount,
- shouldThrowOnInsufficientBalanceOrAllowance,
- takerAddress,
- );
- await zeroEx.awaitTransactionMinedAsync(txHash);
- const filledAmount = await zeroEx.exchange.getFilledTakerAmountAsync(signedOrderHashHex);
- const zeroAmount = await zeroEx.exchange.getFilledTakerAmountAsync(anotherOrderHashHex);
- expect(filledAmount).to.be.bignumber.equal(fillableAmount);
- expect(zeroAmount).to.be.bignumber.equal(0);
- });
- it('should successfully fill up to specified amount even if filling all orders would fail', async () => {
- const missingBalance = new BigNumber(1); // User will still have enough balance to fill up to 9,
- // but won't have 10 to fully fill all orders in a batch.
- await zeroEx.token.transferAsync(makerTokenAddress, makerAddress, coinbase, missingBalance);
- const txHash = await zeroEx.exchange.fillOrdersUpToAsync(
- signedOrders,
- fillUpToAmount,
- shouldThrowOnInsufficientBalanceOrAllowance,
- takerAddress,
- );
- await zeroEx.awaitTransactionMinedAsync(txHash);
- const filledAmount = await zeroEx.exchange.getFilledTakerAmountAsync(signedOrderHashHex);
- const anotherFilledAmount = await zeroEx.exchange.getFilledTakerAmountAsync(anotherOrderHashHex);
- expect(filledAmount).to.be.bignumber.equal(fillableAmount);
- const remainingFillAmount = fillableAmount.minus(1);
- expect(anotherFilledAmount).to.be.bignumber.equal(remainingFillAmount);
- });
- });
- describe('failed batch fills', () => {
- it("should fail validation if user doesn't have enough balance without fill up to", async () => {
- const missingBalance = new BigNumber(2); // User will only have enough balance to fill up to 8
- await zeroEx.token.transferAsync(makerTokenAddress, makerAddress, coinbase, missingBalance);
- return expect(
- zeroEx.exchange.fillOrdersUpToAsync(
- signedOrders,
- fillUpToAmount,
- shouldThrowOnInsufficientBalanceOrAllowance,
- takerAddress,
- ),
- ).to.be.rejectedWith(ExchangeContractErrs.InsufficientMakerBalance);
- });
- });
- describe('order transaction options', () => {
- const emptyFillUpToAmount = new BigNumber(0);
- it('should validate when orderTransactionOptions are not present', async () => {
- return expect(
- zeroEx.exchange.fillOrdersUpToAsync(
- signedOrders,
- emptyFillUpToAmount,
- shouldThrowOnInsufficientBalanceOrAllowance,
- takerAddress,
- ),
- ).to.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero);
- });
- it('should validate when orderTransactionOptions specify to validate', async () => {
- return expect(
- zeroEx.exchange.fillOrdersUpToAsync(
- signedOrders,
- emptyFillUpToAmount,
- shouldThrowOnInsufficientBalanceOrAllowance,
- takerAddress,
- {
- shouldValidate: true,
- },
- ),
- ).to.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero);
- });
- it('should not validate when orderTransactionOptions specify not to validate', async () => {
- return expect(
- zeroEx.exchange.fillOrdersUpToAsync(
- signedOrders,
- emptyFillUpToAmount,
- shouldThrowOnInsufficientBalanceOrAllowance,
- takerAddress,
- {
- shouldValidate: false,
- },
- ),
- ).to.not.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero);
- });
- });
- });
- });
- describe('cancel order(s)', () => {
- let makerTokenAddress: string;
- let takerTokenAddress: string;
- let coinbase: string;
- let makerAddress: string;
- let takerAddress: string;
- const fillableAmount = new BigNumber(5);
- let signedOrder: SignedOrder;
- let orderHashHex: string;
- const cancelAmount = new BigNumber(3);
- beforeEach(async () => {
- [coinbase, makerAddress, takerAddress] = userAddresses;
- const [makerToken, takerToken] = tokenUtils.getDummyTokens();
- makerTokenAddress = makerToken.address;
- takerTokenAddress = takerToken.address;
- signedOrder = await fillScenarios.createFillableSignedOrderAsync(
- makerTokenAddress,
- takerTokenAddress,
- makerAddress,
- takerAddress,
- fillableAmount,
- );
- orderHashHex = ZeroEx.getOrderHashHex(signedOrder);
- });
- describe('#cancelOrderAsync', () => {
- describe('successful cancels', () => {
- it('should cancel an order', async () => {
- const txHash = await zeroEx.exchange.cancelOrderAsync(signedOrder, cancelAmount);
- await zeroEx.awaitTransactionMinedAsync(txHash);
- const cancelledAmount = await zeroEx.exchange.getCancelledTakerAmountAsync(orderHashHex);
- expect(cancelledAmount).to.be.bignumber.equal(cancelAmount);
- });
- });
- describe('order transaction options', () => {
- const emptyCancelTakerTokenAmount = new BigNumber(0);
- it('should validate when orderTransactionOptions are not present', async () => {
- return expect(
- zeroEx.exchange.cancelOrderAsync(signedOrder, emptyCancelTakerTokenAmount),
- ).to.be.rejectedWith(ExchangeContractErrs.OrderCancelAmountZero);
- });
- it('should validate when orderTransactionOptions specify to validate', async () => {
- return expect(
- zeroEx.exchange.cancelOrderAsync(signedOrder, emptyCancelTakerTokenAmount, {
- shouldValidate: true,
- }),
- ).to.be.rejectedWith(ExchangeContractErrs.OrderCancelAmountZero);
- });
- it('should not validate when orderTransactionOptions specify not to validate', async () => {
- return expect(
- zeroEx.exchange.cancelOrderAsync(signedOrder, emptyCancelTakerTokenAmount, {
- shouldValidate: false,
- }),
- ).to.not.be.rejectedWith(ExchangeContractErrs.OrderCancelAmountZero);
- });
- });
- });
- describe('#batchCancelOrdersAsync', () => {
- let anotherSignedOrder: SignedOrder;
- let anotherOrderHashHex: string;
- let cancelBatch: OrderCancellationRequest[];
- beforeEach(async () => {
- anotherSignedOrder = await fillScenarios.createFillableSignedOrderAsync(
- makerTokenAddress,
- takerTokenAddress,
- makerAddress,
- takerAddress,
- fillableAmount,
- );
- anotherOrderHashHex = ZeroEx.getOrderHashHex(anotherSignedOrder);
- cancelBatch = [
- {
- order: signedOrder,
- takerTokenCancelAmount: cancelAmount,
- },
- {
- order: anotherSignedOrder,
- takerTokenCancelAmount: cancelAmount,
- },
- ];
- });
- describe('failed batch cancels', () => {
- it('should throw when orders have different makers', async () => {
- const signedOrderWithDifferentMaker = await fillScenarios.createFillableSignedOrderAsync(
- makerTokenAddress,
- takerTokenAddress,
- takerAddress,
- takerAddress,
- fillableAmount,
- );
- return expect(
- zeroEx.exchange.batchCancelOrdersAsync([
- cancelBatch[0],
- {
- order: signedOrderWithDifferentMaker,
- takerTokenCancelAmount: cancelAmount,
- },
- ]),
- ).to.be.rejectedWith(ExchangeContractErrs.MultipleMakersInSingleCancelBatchDisallowed);
- });
- });
- describe('successful batch cancels', () => {
- it('should cancel a batch of orders', async () => {
- await zeroEx.exchange.batchCancelOrdersAsync(cancelBatch);
- const cancelledAmount = await zeroEx.exchange.getCancelledTakerAmountAsync(orderHashHex);
- const anotherCancelledAmount = await zeroEx.exchange.getCancelledTakerAmountAsync(
- anotherOrderHashHex,
- );
- expect(cancelledAmount).to.be.bignumber.equal(cancelAmount);
- expect(anotherCancelledAmount).to.be.bignumber.equal(cancelAmount);
- });
- });
- describe('order transaction options', () => {
- beforeEach(async () => {
- const emptyTakerTokenCancelAmount = new BigNumber(0);
- cancelBatch = [
- {
- order: signedOrder,
- takerTokenCancelAmount: emptyTakerTokenCancelAmount,
- },
- {
- order: anotherSignedOrder,
- takerTokenCancelAmount: emptyTakerTokenCancelAmount,
- },
- ];
- });
- it('should validate when orderTransactionOptions are not present', async () => {
- return expect(zeroEx.exchange.batchCancelOrdersAsync(cancelBatch)).to.be.rejectedWith(
- ExchangeContractErrs.OrderCancelAmountZero,
- );
- });
- it('should validate when orderTransactionOptions specify to validate', async () => {
- return expect(
- zeroEx.exchange.batchCancelOrdersAsync(cancelBatch, {
- shouldValidate: true,
- }),
- ).to.be.rejectedWith(ExchangeContractErrs.OrderCancelAmountZero);
- });
- it('should not validate when orderTransactionOptions specify not to validate', async () => {
- return expect(
- zeroEx.exchange.batchCancelOrdersAsync(cancelBatch, {
- shouldValidate: false,
- }),
- ).to.not.be.rejectedWith(ExchangeContractErrs.OrderCancelAmountZero);
- });
- });
- });
- });
- describe('tests that require partially filled order', () => {
- let makerTokenAddress: string;
- let takerTokenAddress: string;
- let takerAddress: string;
- let fillableAmount: BigNumber;
- let partialFillAmount: BigNumber;
- let signedOrder: SignedOrder;
- let orderHash: string;
- before(() => {
- takerAddress = userAddresses[1];
- tokenUtils = new TokenUtils(tokens);
- const [makerToken, takerToken] = tokenUtils.getDummyTokens();
- makerTokenAddress = makerToken.address;
- takerTokenAddress = takerToken.address;
- });
- beforeEach(async () => {
- fillableAmount = new BigNumber(5);
- partialFillAmount = new BigNumber(2);
- signedOrder = await fillScenarios.createPartiallyFilledSignedOrderAsync(
- makerTokenAddress,
- takerTokenAddress,
- takerAddress,
- fillableAmount,
- partialFillAmount,
- );
- orderHash = ZeroEx.getOrderHashHex(signedOrder);
- });
- describe('#getUnavailableTakerAmountAsync', () => {
- it('should throw if passed an invalid orderHash', async () => {
- const invalidOrderHashHex = '0x123';
- return expect(zeroEx.exchange.getUnavailableTakerAmountAsync(invalidOrderHashHex)).to.be.rejected();
- });
- it('should return zero if passed a valid but non-existent orderHash', async () => {
- const unavailableValueT = await zeroEx.exchange.getUnavailableTakerAmountAsync(NON_EXISTENT_ORDER_HASH);
- expect(unavailableValueT).to.be.bignumber.equal(0);
- });
- it('should return the unavailableValueT for a valid and partially filled orderHash', async () => {
- const unavailableValueT = await zeroEx.exchange.getUnavailableTakerAmountAsync(orderHash);
- expect(unavailableValueT).to.be.bignumber.equal(partialFillAmount);
- });
- });
- describe('#getFilledTakerAmountAsync', () => {
- it('should throw if passed an invalid orderHash', async () => {
- const invalidOrderHashHex = '0x123';
- return expect(zeroEx.exchange.getFilledTakerAmountAsync(invalidOrderHashHex)).to.be.rejected();
- });
- it('should return zero if passed a valid but non-existent orderHash', async () => {
- const filledValueT = await zeroEx.exchange.getFilledTakerAmountAsync(NON_EXISTENT_ORDER_HASH);
- expect(filledValueT).to.be.bignumber.equal(0);
- });
- it('should return the filledValueT for a valid and partially filled orderHash', async () => {
- const filledValueT = await zeroEx.exchange.getFilledTakerAmountAsync(orderHash);
- expect(filledValueT).to.be.bignumber.equal(partialFillAmount);
- });
- });
- describe('#getCancelledTakerAmountAsync', () => {
- it('should throw if passed an invalid orderHash', async () => {
- const invalidOrderHashHex = '0x123';
- return expect(zeroEx.exchange.getCancelledTakerAmountAsync(invalidOrderHashHex)).to.be.rejected();
- });
- it('should return zero if passed a valid but non-existent orderHash', async () => {
- const cancelledValueT = await zeroEx.exchange.getCancelledTakerAmountAsync(NON_EXISTENT_ORDER_HASH);
- expect(cancelledValueT).to.be.bignumber.equal(0);
- });
- it('should return the cancelledValueT for a valid and partially filled orderHash', async () => {
- const cancelledValueT = await zeroEx.exchange.getCancelledTakerAmountAsync(orderHash);
- expect(cancelledValueT).to.be.bignumber.equal(0);
- });
- it('should return the cancelledValueT for a valid and cancelled orderHash', async () => {
- const cancelAmount = fillableAmount.minus(partialFillAmount);
- await zeroEx.exchange.cancelOrderAsync(signedOrder, cancelAmount);
- const cancelledValueT = await zeroEx.exchange.getCancelledTakerAmountAsync(orderHash);
- expect(cancelledValueT).to.be.bignumber.equal(cancelAmount);
- });
- });
- });
- describe('#subscribe', () => {
- const indexFilterValues = {};
- const shouldThrowOnInsufficientBalanceOrAllowance = true;
- let makerTokenAddress: string;
- let takerTokenAddress: string;
- let coinbase: string;
- let takerAddress: string;
- let makerAddress: string;
- let fillableAmount: BigNumber;
- let signedOrder: SignedOrder;
- const takerTokenFillAmountInBaseUnits = new BigNumber(1);
- const cancelTakerAmountInBaseUnits = new BigNumber(1);
- before(() => {
- [coinbase, makerAddress, takerAddress] = userAddresses;
- const [makerToken, takerToken] = tokenUtils.getDummyTokens();
- makerTokenAddress = makerToken.address;
- takerTokenAddress = takerToken.address;
- });
- beforeEach(async () => {
- fillableAmount = new BigNumber(5);
- signedOrder = await fillScenarios.createFillableSignedOrderAsync(
- makerTokenAddress,
- takerTokenAddress,
- makerAddress,
- takerAddress,
- fillableAmount,
- );
- });
- afterEach(async () => {
- zeroEx.exchange.unsubscribeAll();
- });
- // Hack: Mocha does not allow a test to be both async and have a `done` callback
- // Since we need to await the receipt of the event in the `subscribe` callback,
- // we do need both. A hack is to make the top-level a sync fn w/ a done callback and then
- // wrap the rest of the test in an async block
- // Source: https://github.com/mochajs/mocha/issues/2407
- it('Should receive the LogFill event when an order is filled', (done: DoneCallback) => {
- (async () => {
- const callback = reportNodeCallbackErrors(done)(
- (logEvent: DecodedLogEvent<LogFillContractEventArgs>) => {
- expect(logEvent.log.event).to.be.equal(ExchangeEvents.LogFill);
- },
- );
- zeroEx.exchange.subscribe(ExchangeEvents.LogFill, indexFilterValues, callback);
- await zeroEx.exchange.fillOrderAsync(
- signedOrder,
- takerTokenFillAmountInBaseUnits,
- shouldThrowOnInsufficientBalanceOrAllowance,
- takerAddress,
- );
- })().catch(done);
- });
- it('Should receive the LogCancel event when an order is cancelled', (done: DoneCallback) => {
- (async () => {
- const callback = reportNodeCallbackErrors(done)(
- (logEvent: DecodedLogEvent<LogCancelContractEventArgs>) => {
- expect(logEvent.log.event).to.be.equal(ExchangeEvents.LogCancel);
- },
- );
- zeroEx.exchange.subscribe(ExchangeEvents.LogCancel, indexFilterValues, callback);
- await zeroEx.exchange.cancelOrderAsync(signedOrder, cancelTakerAmountInBaseUnits);
- })().catch(done);
- });
- it('Outstanding subscriptions are cancelled when zeroEx.setProvider called', (done: DoneCallback) => {
- (async () => {
- const callbackNeverToBeCalled = reportNodeCallbackErrors(done)(
- (logEvent: DecodedLogEvent<LogFillContractEventArgs>) => {
- done(new Error('Expected this subscription to have been cancelled'));
- },
- );
- zeroEx.exchange.subscribe(ExchangeEvents.LogFill, indexFilterValues, callbackNeverToBeCalled);
-
- zeroEx.setProvider(provider, constants.TESTRPC_NETWORK_ID);
-
- const callback = reportNodeCallbackErrors(done)(
- (logEvent: DecodedLogEvent<LogFillContractEventArgs>) => {
- expect(logEvent.log.event).to.be.equal(ExchangeEvents.LogFill);
- },
- );
- zeroEx.exchange.subscribe(ExchangeEvents.LogFill, indexFilterValues, callback);
- await zeroEx.exchange.fillOrderAsync(
- signedOrder,
- takerTokenFillAmountInBaseUnits,
- shouldThrowOnInsufficientBalanceOrAllowance,
- takerAddress,
- );
- })().catch(done);
- });
- it('Should cancel subscription when unsubscribe called', (done: DoneCallback) => {
- (async () => {
- const callbackNeverToBeCalled = reportNodeCallbackErrors(done)(
- (logEvent: DecodedLogEvent<LogFillContractEventArgs>) => {
- done(new Error('Expected this subscription to have been cancelled'));
- },
- );
- const subscriptionToken = zeroEx.exchange.subscribe(
- ExchangeEvents.LogFill,
- indexFilterValues,
- callbackNeverToBeCalled,
- );
- zeroEx.exchange.unsubscribe(subscriptionToken);
- await zeroEx.exchange.fillOrderAsync(
- signedOrder,
- takerTokenFillAmountInBaseUnits,
- shouldThrowOnInsufficientBalanceOrAllowance,
- takerAddress,
- );
- done();
- })().catch(done);
- });
- });
- describe('#getOrderHashHexUsingContractCallAsync', () => {
- let makerTokenAddress: string;
- let takerTokenAddress: string;
- let makerAddress: string;
- let takerAddress: string;
- const fillableAmount = new BigNumber(5);
- before(async () => {
- [, makerAddress, takerAddress] = userAddresses;
- const [makerToken, takerToken] = tokenUtils.getDummyTokens();
- makerTokenAddress = makerToken.address;
- takerTokenAddress = takerToken.address;
- });
- it("get's the same hash as the local function", async () => {
- const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
- makerTokenAddress,
- takerTokenAddress,
- makerAddress,
- takerAddress,
- fillableAmount,
- );
- const orderHash = ZeroEx.getOrderHashHex(signedOrder);
- const orderHashFromContract = await (zeroEx.exchange as any)._getOrderHashHexUsingContractCallAsync(
- signedOrder,
- );
- expect(orderHash).to.equal(orderHashFromContract);
- });
- });
- describe('#getZRXTokenAddressAsync', () => {
- it('gets the same token as is in token registry', () => {
- const zrxAddress = zeroEx.exchange.getZRXTokenAddress();
- const zrxToken = tokenUtils.getProtocolTokenOrThrow();
- expect(zrxAddress).to.equal(zrxToken.address);
- });
- });
- describe('#getLogsAsync', () => {
- let makerTokenAddress: string;
- let takerTokenAddress: string;
- let makerAddress: string;
- let takerAddress: string;
- const fillableAmount = new BigNumber(5);
- const shouldThrowOnInsufficientBalanceOrAllowance = true;
- const blockRange: BlockRange = {
- fromBlock: 0,
- toBlock: BlockParamLiteral.Latest,
- };
- let txHash: string;
- before(async () => {
- [, makerAddress, takerAddress] = userAddresses;
- const [makerToken, takerToken] = tokenUtils.getDummyTokens();
- makerTokenAddress = makerToken.address;
- takerTokenAddress = takerToken.address;
- });
- it('should get logs with decoded args emitted by LogFill', async () => {
- const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
- makerTokenAddress,
- takerTokenAddress,
- makerAddress,
- takerAddress,
- fillableAmount,
- );
- txHash = await zeroEx.exchange.fillOrderAsync(
- signedOrder,
- fillableAmount,
- shouldThrowOnInsufficientBalanceOrAllowance,
- takerAddress,
- );
- await zeroEx.awaitTransactionMinedAsync(txHash);
- const eventName = ExchangeEvents.LogFill;
- const indexFilterValues = {};
- const logs = await zeroEx.exchange.getLogsAsync(eventName, blockRange, indexFilterValues);
- expect(logs).to.have.length(1);
- expect(logs[0].event).to.be.equal(eventName);
- });
- it('should only get the logs with the correct event name', async () => {
- const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
- makerTokenAddress,
- takerTokenAddress,
- makerAddress,
- takerAddress,
- fillableAmount,
- );
- txHash = await zeroEx.exchange.fillOrderAsync(
- signedOrder,
- fillableAmount,
- shouldThrowOnInsufficientBalanceOrAllowance,
- takerAddress,
- );
- await zeroEx.awaitTransactionMinedAsync(txHash);
- const differentEventName = ExchangeEvents.LogCancel;
- const indexFilterValues = {};
- const logs = await zeroEx.exchange.getLogsAsync(differentEventName, blockRange, indexFilterValues);
- expect(logs).to.have.length(0);
- });
- it('should only get the logs with the correct indexed fields', async () => {
- const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
- makerTokenAddress,
- takerTokenAddress,
- makerAddress,
- takerAddress,
- fillableAmount,
- );
- txHash = await zeroEx.exchange.fillOrderAsync(
- signedOrder,
- fillableAmount,
- shouldThrowOnInsufficientBalanceOrAllowance,
- takerAddress,
- );
- await zeroEx.awaitTransactionMinedAsync(txHash);
-
- const differentMakerAddress = userAddresses[2];
- const anotherSignedOrder = await fillScenarios.createFillableSignedOrderAsync(
- makerTokenAddress,
- takerTokenAddress,
- differentMakerAddress,
- takerAddress,
- fillableAmount,
- );
- txHash = await zeroEx.exchange.fillOrderAsync(
- anotherSignedOrder,
- fillableAmount,
- shouldThrowOnInsufficientBalanceOrAllowance,
- takerAddress,
- );
- await zeroEx.awaitTransactionMinedAsync(txHash);
-
- const eventName = ExchangeEvents.LogFill;
- const indexFilterValues = {
- maker: differentMakerAddress,
- };
- const logs = await zeroEx.exchange.getLogsAsync<LogFillContractEventArgs>(
- eventName,
- blockRange,
- indexFilterValues,
- );
- expect(logs).to.have.length(1);
- const args = logs[0].args;
- expect(args.maker).to.be.equal(differentMakerAddress);
- });
- });
- describe('#getOrderStateAsync', () => {
- let maker: string;
- let taker: string;
- let makerToken: Token;
- let takerToken: Token;
- let signedOrder: SignedOrder;
- let orderState: OrderState;
- const fillableAmount = ZeroEx.toBaseUnitAmount(new BigNumber(5), constants.ZRX_DECIMALS);
- before(async () => {
- [, maker, taker] = userAddresses;
- tokens = await zeroEx.tokenRegistry.getTokensAsync();
- [makerToken, takerToken] = tokenUtils.getDummyTokens();
- });
- it('should report orderStateValid when order is fillable', async () => {
- signedOrder = await fillScenarios.createFillableSignedOrderAsync(
- makerToken.address,
- takerToken.address,
- maker,
- taker,
- fillableAmount,
- );
- orderState = await zeroEx.exchange.getOrderStateAsync(signedOrder);
- expect(orderState.isValid).to.be.true();
- });
- it('should report orderStateInvalid when maker allowance set to 0', async () => {
- signedOrder = await fillScenarios.createFillableSignedOrderAsync(
- makerToken.address,
- takerToken.address,
- maker,
- taker,
- fillableAmount,
- );
- await zeroEx.token.setProxyAllowanceAsync(makerToken.address, maker, new BigNumber(0));
- orderState = await zeroEx.exchange.getOrderStateAsync(signedOrder);
- expect(orderState.isValid).to.be.false();
- });
- });
-}); // tslint:disable:max-file-line-count
diff --git a/packages/0x.js/test/expiration_watcher_test.ts b/packages/0x.js/test/expiration_watcher_test.ts
deleted file mode 100644
index 1b022539a..000000000
--- a/packages/0x.js/test/expiration_watcher_test.ts
+++ /dev/null
@@ -1,195 +0,0 @@
-import { BlockchainLifecycle, devConstants } from '@0xproject/dev-utils';
-import { BigNumber } from '@0xproject/utils';
-import * as chai from 'chai';
-import * as _ from 'lodash';
-import 'mocha';
-import * as Sinon from 'sinon';
-
-import { ZeroEx } from '../src/0x';
-import { ExpirationWatcher } from '../src/order_watcher/expiration_watcher';
-import { DoneCallback, Token } from '../src/types';
-import { utils } from '../src/utils/utils';
-
-import { chaiSetup } from './utils/chai_setup';
-import { constants } from './utils/constants';
-import { FillScenarios } from './utils/fill_scenarios';
-import { reportNoErrorCallbackErrors } from './utils/report_callback_errors';
-import { TokenUtils } from './utils/token_utils';
-import { provider, web3Wrapper } from './utils/web3_wrapper';
-
-chaiSetup.configure();
-const expect = chai.expect;
-const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
-
-describe('ExpirationWatcher', () => {
- let zeroEx: ZeroEx;
- let tokenUtils: TokenUtils;
- let tokens: Token[];
- let userAddresses: string[];
- let zrxTokenAddress: string;
- let fillScenarios: FillScenarios;
- let exchangeContractAddress: string;
- let makerTokenAddress: string;
- let takerTokenAddress: string;
- let coinbase: string;
- let makerAddress: string;
- let takerAddress: string;
- let feeRecipient: string;
- const fillableAmount = new BigNumber(5);
- let currentUnixTimestampSec: BigNumber;
- let timer: Sinon.SinonFakeTimers;
- let expirationWatcher: ExpirationWatcher;
- before(async () => {
- const config = {
- networkId: constants.TESTRPC_NETWORK_ID,
- };
- zeroEx = new ZeroEx(provider, config);
- exchangeContractAddress = zeroEx.exchange.getContractAddress();
- userAddresses = await zeroEx.getAvailableAddressesAsync();
- tokens = await zeroEx.tokenRegistry.getTokensAsync();
- tokenUtils = new TokenUtils(tokens);
- zrxTokenAddress = tokenUtils.getProtocolTokenOrThrow().address;
- fillScenarios = new FillScenarios(zeroEx, userAddresses, tokens, zrxTokenAddress, exchangeContractAddress);
- [coinbase, makerAddress, takerAddress, feeRecipient] = userAddresses;
- tokens = await zeroEx.tokenRegistry.getTokensAsync();
- const [makerToken, takerToken] = tokenUtils.getDummyTokens();
- makerTokenAddress = makerToken.address;
- takerTokenAddress = takerToken.address;
- });
- beforeEach(async () => {
- await blockchainLifecycle.startAsync();
- const sinonTimerConfig = { shouldAdvanceTime: true } as any;
- // This constructor has incorrect types
- timer = Sinon.useFakeTimers(sinonTimerConfig);
- currentUnixTimestampSec = utils.getCurrentUnixTimestampSec();
- expirationWatcher = new ExpirationWatcher();
- });
- afterEach(async () => {
- await blockchainLifecycle.revertAsync();
- timer.restore();
- expirationWatcher.unsubscribe();
- });
- it('correctly emits events when order expires', (done: DoneCallback) => {
- (async () => {
- const orderLifetimeSec = 60;
- const expirationUnixTimestampSec = currentUnixTimestampSec.plus(orderLifetimeSec);
- const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
- makerTokenAddress,
- takerTokenAddress,
- makerAddress,
- takerAddress,
- fillableAmount,
- expirationUnixTimestampSec,
- );
- const orderHash = ZeroEx.getOrderHashHex(signedOrder);
- expirationWatcher.addOrder(orderHash, signedOrder.expirationUnixTimestampSec.times(1000));
- const callbackAsync = reportNoErrorCallbackErrors(done)((hash: string) => {
- expect(hash).to.be.equal(orderHash);
- expect(utils.getCurrentUnixTimestampSec()).to.be.bignumber.gte(expirationUnixTimestampSec);
- });
- expirationWatcher.subscribe(callbackAsync);
- timer.tick(orderLifetimeSec * 1000);
- })().catch(done);
- });
- it("doesn't emit events before order expires", (done: DoneCallback) => {
- (async () => {
- const orderLifetimeSec = 60;
- const expirationUnixTimestampSec = currentUnixTimestampSec.plus(orderLifetimeSec);
- const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
- makerTokenAddress,
- takerTokenAddress,
- makerAddress,
- takerAddress,
- fillableAmount,
- expirationUnixTimestampSec,
- );
- const orderHash = ZeroEx.getOrderHashHex(signedOrder);
- expirationWatcher.addOrder(orderHash, signedOrder.expirationUnixTimestampSec.times(1000));
- const callbackAsync = reportNoErrorCallbackErrors(done)(async (hash: string) => {
- done(new Error('Emitted expiration went before the order actually expired'));
- });
- expirationWatcher.subscribe(callbackAsync);
- const notEnoughTime = orderLifetimeSec - 1;
- timer.tick(notEnoughTime * 1000);
- done();
- })().catch(done);
- });
- it('emits events in correct order', (done: DoneCallback) => {
- (async () => {
- const order1Lifetime = 60;
- const order2Lifetime = 120;
- const order1ExpirationUnixTimestampSec = currentUnixTimestampSec.plus(order1Lifetime);
- const order2ExpirationUnixTimestampSec = currentUnixTimestampSec.plus(order2Lifetime);
- const signedOrder1 = await fillScenarios.createFillableSignedOrderAsync(
- makerTokenAddress,
- takerTokenAddress,
- makerAddress,
- takerAddress,
- fillableAmount,
- order1ExpirationUnixTimestampSec,
- );
- const signedOrder2 = await fillScenarios.createFillableSignedOrderAsync(
- makerTokenAddress,
- takerTokenAddress,
- makerAddress,
- takerAddress,
- fillableAmount,
- order2ExpirationUnixTimestampSec,
- );
- const orderHash1 = ZeroEx.getOrderHashHex(signedOrder1);
- const orderHash2 = ZeroEx.getOrderHashHex(signedOrder2);
- expirationWatcher.addOrder(orderHash2, signedOrder2.expirationUnixTimestampSec.times(1000));
- expirationWatcher.addOrder(orderHash1, signedOrder1.expirationUnixTimestampSec.times(1000));
- const expirationOrder = [orderHash1, orderHash2];
- const expectToBeCalledOnce = false;
- const callbackAsync = reportNoErrorCallbackErrors(done, expectToBeCalledOnce)((hash: string) => {
- const orderHash = expirationOrder.shift();
- expect(hash).to.be.equal(orderHash);
- if (_.isEmpty(expirationOrder)) {
- done();
- }
- });
- expirationWatcher.subscribe(callbackAsync);
- timer.tick(order2Lifetime * 1000);
- })().catch(done);
- });
- it('emits events in correct order when expirations are equal', (done: DoneCallback) => {
- (async () => {
- const order1Lifetime = 60;
- const order2Lifetime = 60;
- const order1ExpirationUnixTimestampSec = currentUnixTimestampSec.plus(order1Lifetime);
- const order2ExpirationUnixTimestampSec = currentUnixTimestampSec.plus(order2Lifetime);
- const signedOrder1 = await fillScenarios.createFillableSignedOrderAsync(
- makerTokenAddress,
- takerTokenAddress,
- makerAddress,
- takerAddress,
- fillableAmount,
- order1ExpirationUnixTimestampSec,
- );
- const signedOrder2 = await fillScenarios.createFillableSignedOrderAsync(
- makerTokenAddress,
- takerTokenAddress,
- makerAddress,
- takerAddress,
- fillableAmount,
- order2ExpirationUnixTimestampSec,
- );
- const orderHash1 = ZeroEx.getOrderHashHex(signedOrder1);
- const orderHash2 = ZeroEx.getOrderHashHex(signedOrder2);
- expirationWatcher.addOrder(orderHash1, signedOrder1.expirationUnixTimestampSec.times(1000));
- expirationWatcher.addOrder(orderHash2, signedOrder2.expirationUnixTimestampSec.times(1000));
- const expirationOrder = orderHash1 < orderHash2 ? [orderHash1, orderHash2] : [orderHash2, orderHash1];
- const expectToBeCalledOnce = false;
- const callbackAsync = reportNoErrorCallbackErrors(done, expectToBeCalledOnce)((hash: string) => {
- const orderHash = expirationOrder.shift();
- expect(hash).to.be.equal(orderHash);
- if (_.isEmpty(expirationOrder)) {
- done();
- }
- });
- expirationWatcher.subscribe(callbackAsync);
- timer.tick(order2Lifetime * 1000);
- })().catch(done);
- });
-});
diff --git a/packages/0x.js/test/order_state_watcher_test.ts b/packages/0x.js/test/order_state_watcher_test.ts
deleted file mode 100644
index 45a292c8b..000000000
--- a/packages/0x.js/test/order_state_watcher_test.ts
+++ /dev/null
@@ -1,558 +0,0 @@
-import { BlockchainLifecycle, devConstants } from '@0xproject/dev-utils';
-import { BigNumber } from '@0xproject/utils';
-import * as chai from 'chai';
-import * as _ from 'lodash';
-import 'mocha';
-
-import {
- ExchangeContractErrs,
- OrderState,
- OrderStateInvalid,
- OrderStateValid,
- SignedOrder,
- Token,
- ZeroEx,
- ZeroExError,
-} from '../src';
-import { OrderStateWatcher } from '../src/order_watcher/order_state_watcher';
-import { DoneCallback } from '../src/types';
-
-import { chaiSetup } from './utils/chai_setup';
-import { constants } from './utils/constants';
-import { FillScenarios } from './utils/fill_scenarios';
-import { reportNodeCallbackErrors } from './utils/report_callback_errors';
-import { TokenUtils } from './utils/token_utils';
-import { provider, web3Wrapper } from './utils/web3_wrapper';
-
-const TIMEOUT_MS = 150;
-
-chaiSetup.configure();
-const expect = chai.expect;
-const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
-
-describe('OrderStateWatcher', () => {
- let zeroEx: ZeroEx;
- let tokens: Token[];
- let tokenUtils: TokenUtils;
- let fillScenarios: FillScenarios;
- let userAddresses: string[];
- let zrxTokenAddress: string;
- let exchangeContractAddress: string;
- let makerToken: Token;
- let takerToken: Token;
- let maker: string;
- let taker: string;
- let signedOrder: SignedOrder;
- let orderStateWatcher: OrderStateWatcher;
- const config = {
- networkId: constants.TESTRPC_NETWORK_ID,
- };
- const decimals = constants.ZRX_DECIMALS;
- const fillableAmount = ZeroEx.toBaseUnitAmount(new BigNumber(5), decimals);
- before(async () => {
- zeroEx = new ZeroEx(provider, config);
- orderStateWatcher = zeroEx.createOrderStateWatcher();
- exchangeContractAddress = zeroEx.exchange.getContractAddress();
- userAddresses = await zeroEx.getAvailableAddressesAsync();
- [, maker, taker] = userAddresses;
- tokens = await zeroEx.tokenRegistry.getTokensAsync();
- tokenUtils = new TokenUtils(tokens);
- zrxTokenAddress = tokenUtils.getProtocolTokenOrThrow().address;
- fillScenarios = new FillScenarios(zeroEx, userAddresses, tokens, zrxTokenAddress, exchangeContractAddress);
- await fillScenarios.initTokenBalancesAsync();
- [makerToken, takerToken] = tokenUtils.getDummyTokens();
- });
- beforeEach(async () => {
- await blockchainLifecycle.startAsync();
- });
- afterEach(async () => {
- await blockchainLifecycle.revertAsync();
- });
- describe('#removeOrder', async () => {
- it('should successfully remove existing order', async () => {
- signedOrder = await fillScenarios.createFillableSignedOrderAsync(
- makerToken.address,
- takerToken.address,
- maker,
- taker,
- fillableAmount,
- );
- const orderHash = ZeroEx.getOrderHashHex(signedOrder);
- orderStateWatcher.addOrder(signedOrder);
- expect((orderStateWatcher as any)._orderByOrderHash).to.include({
- [orderHash]: signedOrder,
- });
- let dependentOrderHashes = (orderStateWatcher as any)._dependentOrderHashes;
- expect(dependentOrderHashes[signedOrder.maker][signedOrder.makerTokenAddress]).to.have.keys(orderHash);
- orderStateWatcher.removeOrder(orderHash);
- expect((orderStateWatcher as any)._orderByOrderHash).to.not.include({
- [orderHash]: signedOrder,
- });
- dependentOrderHashes = (orderStateWatcher as any)._dependentOrderHashes;
- expect(dependentOrderHashes[signedOrder.maker]).to.be.undefined();
- });
- it('should no-op when removing a non-existing order', async () => {
- signedOrder = await fillScenarios.createFillableSignedOrderAsync(
- makerToken.address,
- takerToken.address,
- maker,
- taker,
- fillableAmount,
- );
- const orderHash = ZeroEx.getOrderHashHex(signedOrder);
- const nonExistentOrderHash = `0x${orderHash
- .substr(2)
- .split('')
- .reverse()
- .join('')}`;
- orderStateWatcher.removeOrder(nonExistentOrderHash);
- });
- });
- describe('#subscribe', async () => {
- afterEach(async () => {
- orderStateWatcher.unsubscribe();
- });
- it('should fail when trying to subscribe twice', async () => {
- orderStateWatcher.subscribe(_.noop);
- expect(() => orderStateWatcher.subscribe(_.noop)).to.throw(ZeroExError.SubscriptionAlreadyPresent);
- });
- });
- describe('tests with cleanup', async () => {
- afterEach(async () => {
- orderStateWatcher.unsubscribe();
- const orderHash = ZeroEx.getOrderHashHex(signedOrder);
- orderStateWatcher.removeOrder(orderHash);
- });
- it('should emit orderStateInvalid when maker allowance set to 0 for watched order', (done: DoneCallback) => {
- (async () => {
- signedOrder = await fillScenarios.createFillableSignedOrderAsync(
- makerToken.address,
- takerToken.address,
- maker,
- taker,
- fillableAmount,
- );
- const orderHash = ZeroEx.getOrderHashHex(signedOrder);
- orderStateWatcher.addOrder(signedOrder);
- const callback = reportNodeCallbackErrors(done)((orderState: OrderState) => {
- expect(orderState.isValid).to.be.false();
- const invalidOrderState = orderState as OrderStateInvalid;
- expect(invalidOrderState.orderHash).to.be.equal(orderHash);
- expect(invalidOrderState.error).to.be.equal(ExchangeContractErrs.InsufficientMakerAllowance);
- });
- orderStateWatcher.subscribe(callback);
- await zeroEx.token.setProxyAllowanceAsync(makerToken.address, maker, new BigNumber(0));
- })().catch(done);
- });
- it('should not emit an orderState event when irrelevant Transfer event received', (done: DoneCallback) => {
- (async () => {
- signedOrder = await fillScenarios.createFillableSignedOrderAsync(
- makerToken.address,
- takerToken.address,
- maker,
- taker,
- fillableAmount,
- );
- orderStateWatcher.addOrder(signedOrder);
- const callback = reportNodeCallbackErrors(done)((orderState: OrderState) => {
- throw new Error('OrderState callback fired for irrelevant order');
- });
- orderStateWatcher.subscribe(callback);
- const notTheMaker = userAddresses[0];
- const anyRecipient = taker;
- const transferAmount = new BigNumber(2);
- await zeroEx.token.transferAsync(makerToken.address, notTheMaker, anyRecipient, transferAmount);
- setTimeout(() => {
- done();
- }, TIMEOUT_MS);
- })().catch(done);
- });
- it('should emit orderStateInvalid when maker moves balance backing watched order', (done: DoneCallback) => {
- (async () => {
- signedOrder = await fillScenarios.createFillableSignedOrderAsync(
- makerToken.address,
- takerToken.address,
- maker,
- taker,
- fillableAmount,
- );
- const orderHash = ZeroEx.getOrderHashHex(signedOrder);
- orderStateWatcher.addOrder(signedOrder);
- const callback = reportNodeCallbackErrors(done)((orderState: OrderState) => {
- expect(orderState.isValid).to.be.false();
- const invalidOrderState = orderState as OrderStateInvalid;
- expect(invalidOrderState.orderHash).to.be.equal(orderHash);
- expect(invalidOrderState.error).to.be.equal(ExchangeContractErrs.InsufficientMakerBalance);
- });
- orderStateWatcher.subscribe(callback);
- const anyRecipient = taker;
- const makerBalance = await zeroEx.token.getBalanceAsync(makerToken.address, maker);
- await zeroEx.token.transferAsync(makerToken.address, maker, anyRecipient, makerBalance);
- })().catch(done);
- });
- it('should emit orderStateInvalid when watched order fully filled', (done: DoneCallback) => {
- (async () => {
- signedOrder = await fillScenarios.createFillableSignedOrderAsync(
- makerToken.address,
- takerToken.address,
- maker,
- taker,
- fillableAmount,
- );
- const orderHash = ZeroEx.getOrderHashHex(signedOrder);
- orderStateWatcher.addOrder(signedOrder);
-
- const callback = reportNodeCallbackErrors(done)((orderState: OrderState) => {
- expect(orderState.isValid).to.be.false();
- const invalidOrderState = orderState as OrderStateInvalid;
- expect(invalidOrderState.orderHash).to.be.equal(orderHash);
- expect(invalidOrderState.error).to.be.equal(ExchangeContractErrs.OrderRemainingFillAmountZero);
- });
- orderStateWatcher.subscribe(callback);
-
- const shouldThrowOnInsufficientBalanceOrAllowance = true;
- await zeroEx.exchange.fillOrderAsync(
- signedOrder,
- fillableAmount,
- shouldThrowOnInsufficientBalanceOrAllowance,
- taker,
- );
- })().catch(done);
- });
- it('should emit orderStateValid when watched order partially filled', (done: DoneCallback) => {
- (async () => {
- signedOrder = await fillScenarios.createFillableSignedOrderAsync(
- makerToken.address,
- takerToken.address,
- maker,
- taker,
- fillableAmount,
- );
-
- const makerBalance = await zeroEx.token.getBalanceAsync(makerToken.address, maker);
- const fillAmountInBaseUnits = new BigNumber(2);
- const orderHash = ZeroEx.getOrderHashHex(signedOrder);
- orderStateWatcher.addOrder(signedOrder);
-
- const callback = reportNodeCallbackErrors(done)((orderState: OrderState) => {
- expect(orderState.isValid).to.be.true();
- const validOrderState = orderState as OrderStateValid;
- expect(validOrderState.orderHash).to.be.equal(orderHash);
- const orderRelevantState = validOrderState.orderRelevantState;
- const remainingMakerBalance = makerBalance.sub(fillAmountInBaseUnits);
- const remainingFillable = fillableAmount.minus(fillAmountInBaseUnits);
- expect(orderRelevantState.remainingFillableMakerTokenAmount).to.be.bignumber.equal(
- remainingFillable,
- );
- expect(orderRelevantState.remainingFillableTakerTokenAmount).to.be.bignumber.equal(
- remainingFillable,
- );
- expect(orderRelevantState.makerBalance).to.be.bignumber.equal(remainingMakerBalance);
- });
- orderStateWatcher.subscribe(callback);
- const shouldThrowOnInsufficientBalanceOrAllowance = true;
- await zeroEx.exchange.fillOrderAsync(
- signedOrder,
- fillAmountInBaseUnits,
- shouldThrowOnInsufficientBalanceOrAllowance,
- taker,
- );
- })().catch(done);
- });
- it('should trigger the callback when orders backing ZRX allowance changes', (done: DoneCallback) => {
- (async () => {
- const makerFee = ZeroEx.toBaseUnitAmount(new BigNumber(2), 18);
- const takerFee = ZeroEx.toBaseUnitAmount(new BigNumber(0), 18);
- signedOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync(
- makerToken.address,
- takerToken.address,
- makerFee,
- takerFee,
- maker,
- taker,
- fillableAmount,
- taker,
- );
- const callback = reportNodeCallbackErrors(done)();
- orderStateWatcher.addOrder(signedOrder);
- orderStateWatcher.subscribe(callback);
- await zeroEx.token.setProxyAllowanceAsync(zrxTokenAddress, maker, new BigNumber(0));
- })().catch(done);
- });
- describe('remainingFillable(M|T)akerTokenAmount', () => {
- it('should calculate correct remaining fillable', (done: DoneCallback) => {
- (async () => {
- const takerFillableAmount = ZeroEx.toBaseUnitAmount(new BigNumber(10), decimals);
- const makerFillableAmount = ZeroEx.toBaseUnitAmount(new BigNumber(20), decimals);
- signedOrder = await fillScenarios.createAsymmetricFillableSignedOrderAsync(
- makerToken.address,
- takerToken.address,
- maker,
- taker,
- makerFillableAmount,
- takerFillableAmount,
- );
- const fillAmountInBaseUnits = ZeroEx.toBaseUnitAmount(new BigNumber(2), decimals);
- const orderHash = ZeroEx.getOrderHashHex(signedOrder);
- orderStateWatcher.addOrder(signedOrder);
- const callback = reportNodeCallbackErrors(done)((orderState: OrderState) => {
- expect(orderState.isValid).to.be.true();
- const validOrderState = orderState as OrderStateValid;
- expect(validOrderState.orderHash).to.be.equal(orderHash);
- const orderRelevantState = validOrderState.orderRelevantState;
- expect(orderRelevantState.remainingFillableMakerTokenAmount).to.be.bignumber.equal(
- ZeroEx.toBaseUnitAmount(new BigNumber(16), decimals),
- );
- expect(orderRelevantState.remainingFillableTakerTokenAmount).to.be.bignumber.equal(
- ZeroEx.toBaseUnitAmount(new BigNumber(8), decimals),
- );
- });
- orderStateWatcher.subscribe(callback);
- const shouldThrowOnInsufficientBalanceOrAllowance = true;
- await zeroEx.exchange.fillOrderAsync(
- signedOrder,
- fillAmountInBaseUnits,
- shouldThrowOnInsufficientBalanceOrAllowance,
- taker,
- );
- })().catch(done);
- });
- it('should equal approved amount when approved amount is lowest', (done: DoneCallback) => {
- (async () => {
- signedOrder = await fillScenarios.createFillableSignedOrderAsync(
- makerToken.address,
- takerToken.address,
- maker,
- taker,
- fillableAmount,
- );
-
- const changedMakerApprovalAmount = ZeroEx.toBaseUnitAmount(new BigNumber(3), decimals);
- orderStateWatcher.addOrder(signedOrder);
-
- const callback = reportNodeCallbackErrors(done)((orderState: OrderState) => {
- const validOrderState = orderState as OrderStateValid;
- const orderRelevantState = validOrderState.orderRelevantState;
- expect(orderRelevantState.remainingFillableMakerTokenAmount).to.be.bignumber.equal(
- changedMakerApprovalAmount,
- );
- expect(orderRelevantState.remainingFillableTakerTokenAmount).to.be.bignumber.equal(
- changedMakerApprovalAmount,
- );
- });
- orderStateWatcher.subscribe(callback);
- await zeroEx.token.setProxyAllowanceAsync(makerToken.address, maker, changedMakerApprovalAmount);
- })().catch(done);
- });
- it('should equal balance amount when balance amount is lowest', (done: DoneCallback) => {
- (async () => {
- signedOrder = await fillScenarios.createFillableSignedOrderAsync(
- makerToken.address,
- takerToken.address,
- maker,
- taker,
- fillableAmount,
- );
-
- const makerBalance = await zeroEx.token.getBalanceAsync(makerToken.address, maker);
-
- const remainingAmount = ZeroEx.toBaseUnitAmount(new BigNumber(1), decimals);
- const transferAmount = makerBalance.sub(remainingAmount);
- orderStateWatcher.addOrder(signedOrder);
-
- const callback = reportNodeCallbackErrors(done)((orderState: OrderState) => {
- expect(orderState.isValid).to.be.true();
- const validOrderState = orderState as OrderStateValid;
- const orderRelevantState = validOrderState.orderRelevantState;
- expect(orderRelevantState.remainingFillableMakerTokenAmount).to.be.bignumber.equal(
- remainingAmount,
- );
- expect(orderRelevantState.remainingFillableTakerTokenAmount).to.be.bignumber.equal(
- remainingAmount,
- );
- });
- orderStateWatcher.subscribe(callback);
- await zeroEx.token.transferAsync(makerToken.address, maker, ZeroEx.NULL_ADDRESS, transferAmount);
- })().catch(done);
- });
- it('should equal remaining amount when partially cancelled and order has fees', (done: DoneCallback) => {
- (async () => {
- const takerFee = ZeroEx.toBaseUnitAmount(new BigNumber(0), decimals);
- const makerFee = ZeroEx.toBaseUnitAmount(new BigNumber(5), decimals);
- const feeRecipient = taker;
- signedOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync(
- makerToken.address,
- takerToken.address,
- makerFee,
- takerFee,
- maker,
- taker,
- fillableAmount,
- feeRecipient,
- );
-
- const remainingTokenAmount = ZeroEx.toBaseUnitAmount(new BigNumber(4), decimals);
- const transferTokenAmount = makerFee.sub(remainingTokenAmount);
- orderStateWatcher.addOrder(signedOrder);
-
- const callback = reportNodeCallbackErrors(done)((orderState: OrderState) => {
- expect(orderState.isValid).to.be.true();
- const validOrderState = orderState as OrderStateValid;
- const orderRelevantState = validOrderState.orderRelevantState;
- expect(orderRelevantState.remainingFillableMakerTokenAmount).to.be.bignumber.equal(
- remainingTokenAmount,
- );
- });
- orderStateWatcher.subscribe(callback);
- await zeroEx.exchange.cancelOrderAsync(signedOrder, transferTokenAmount);
- })().catch(done);
- });
- it('should equal ratio amount when fee balance is lowered', (done: DoneCallback) => {
- (async () => {
- const takerFee = ZeroEx.toBaseUnitAmount(new BigNumber(0), decimals);
- const makerFee = ZeroEx.toBaseUnitAmount(new BigNumber(5), decimals);
- const feeRecipient = taker;
- signedOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync(
- makerToken.address,
- takerToken.address,
- makerFee,
- takerFee,
- maker,
- taker,
- fillableAmount,
- feeRecipient,
- );
-
- const remainingFeeAmount = ZeroEx.toBaseUnitAmount(new BigNumber(3), decimals);
-
- const remainingTokenAmount = ZeroEx.toBaseUnitAmount(new BigNumber(4), decimals);
- const transferTokenAmount = makerFee.sub(remainingTokenAmount);
- orderStateWatcher.addOrder(signedOrder);
-
- const callback = reportNodeCallbackErrors(done)((orderState: OrderState) => {
- const validOrderState = orderState as OrderStateValid;
- const orderRelevantState = validOrderState.orderRelevantState;
- expect(orderRelevantState.remainingFillableMakerTokenAmount).to.be.bignumber.equal(
- remainingFeeAmount,
- );
- });
- orderStateWatcher.subscribe(callback);
- await zeroEx.token.setProxyAllowanceAsync(zrxTokenAddress, maker, remainingFeeAmount);
- await zeroEx.token.transferAsync(
- makerToken.address,
- maker,
- ZeroEx.NULL_ADDRESS,
- transferTokenAmount,
- );
- })().catch(done);
- });
- it('should calculate full amount when all available and non-divisible', (done: DoneCallback) => {
- (async () => {
- const takerFee = ZeroEx.toBaseUnitAmount(new BigNumber(0), decimals);
- const makerFee = ZeroEx.toBaseUnitAmount(new BigNumber(2), decimals);
- const feeRecipient = taker;
- signedOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync(
- makerToken.address,
- takerToken.address,
- makerFee,
- takerFee,
- maker,
- taker,
- fillableAmount,
- feeRecipient,
- );
-
- orderStateWatcher.addOrder(signedOrder);
-
- const callback = reportNodeCallbackErrors(done)((orderState: OrderState) => {
- const validOrderState = orderState as OrderStateValid;
- const orderRelevantState = validOrderState.orderRelevantState;
- expect(orderRelevantState.remainingFillableMakerTokenAmount).to.be.bignumber.equal(
- fillableAmount,
- );
- });
- orderStateWatcher.subscribe(callback);
- await zeroEx.token.setProxyAllowanceAsync(
- makerToken.address,
- maker,
- ZeroEx.toBaseUnitAmount(new BigNumber(100), decimals),
- );
- })().catch(done);
- });
- });
- it('should emit orderStateInvalid when watched order cancelled', (done: DoneCallback) => {
- (async () => {
- signedOrder = await fillScenarios.createFillableSignedOrderAsync(
- makerToken.address,
- takerToken.address,
- maker,
- taker,
- fillableAmount,
- );
- const orderHash = ZeroEx.getOrderHashHex(signedOrder);
- orderStateWatcher.addOrder(signedOrder);
-
- const callback = reportNodeCallbackErrors(done)((orderState: OrderState) => {
- expect(orderState.isValid).to.be.false();
- const invalidOrderState = orderState as OrderStateInvalid;
- expect(invalidOrderState.orderHash).to.be.equal(orderHash);
- expect(invalidOrderState.error).to.be.equal(ExchangeContractErrs.OrderRemainingFillAmountZero);
- });
- orderStateWatcher.subscribe(callback);
-
- await zeroEx.exchange.cancelOrderAsync(signedOrder, fillableAmount);
- })().catch(done);
- });
- it('should emit orderStateInvalid when within rounding error range', (done: DoneCallback) => {
- (async () => {
- const remainingFillableAmountInBaseUnits = new BigNumber(100);
- signedOrder = await fillScenarios.createFillableSignedOrderAsync(
- makerToken.address,
- takerToken.address,
- maker,
- taker,
- fillableAmount,
- );
- const orderHash = ZeroEx.getOrderHashHex(signedOrder);
- orderStateWatcher.addOrder(signedOrder);
-
- const callback = reportNodeCallbackErrors(done)((orderState: OrderState) => {
- expect(orderState.isValid).to.be.false();
- const invalidOrderState = orderState as OrderStateInvalid;
- expect(invalidOrderState.orderHash).to.be.equal(orderHash);
- expect(invalidOrderState.error).to.be.equal(ExchangeContractErrs.OrderFillRoundingError);
- });
- orderStateWatcher.subscribe(callback);
- await zeroEx.exchange.cancelOrderAsync(
- signedOrder,
- fillableAmount.minus(remainingFillableAmountInBaseUnits),
- );
- })().catch(done);
- });
- it('should emit orderStateValid when watched order partially cancelled', (done: DoneCallback) => {
- (async () => {
- signedOrder = await fillScenarios.createFillableSignedOrderAsync(
- makerToken.address,
- takerToken.address,
- maker,
- taker,
- fillableAmount,
- );
-
- const cancelAmountInBaseUnits = new BigNumber(2);
- const orderHash = ZeroEx.getOrderHashHex(signedOrder);
- orderStateWatcher.addOrder(signedOrder);
-
- const callback = reportNodeCallbackErrors(done)((orderState: OrderState) => {
- expect(orderState.isValid).to.be.true();
- const validOrderState = orderState as OrderStateValid;
- expect(validOrderState.orderHash).to.be.equal(orderHash);
- const orderRelevantState = validOrderState.orderRelevantState;
- expect(orderRelevantState.cancelledTakerTokenAmount).to.be.bignumber.equal(cancelAmountInBaseUnits);
- });
- orderStateWatcher.subscribe(callback);
- await zeroEx.exchange.cancelOrderAsync(signedOrder, cancelAmountInBaseUnits);
- })().catch(done);
- });
- });
-}); // tslint:disable:max-file-line-count
diff --git a/packages/0x.js/test/order_validation_test.ts b/packages/0x.js/test/order_validation_test.ts
deleted file mode 100644
index 0cb95c1b6..000000000
--- a/packages/0x.js/test/order_validation_test.ts
+++ /dev/null
@@ -1,507 +0,0 @@
-import { BlockchainLifecycle, devConstants } from '@0xproject/dev-utils';
-import { OrderError } from '@0xproject/order-utils';
-import { BlockParamLiteral } from '@0xproject/types';
-import { BigNumber } from '@0xproject/utils';
-import * as chai from 'chai';
-import * as Sinon from 'sinon';
-
-import { ExchangeContractErrs, SignedOrder, Token, ZeroEx, ZeroExError } from '../src';
-import { TradeSide, TransferType } from '../src/types';
-import { ExchangeTransferSimulator } from '../src/utils/exchange_transfer_simulator';
-import { OrderValidationUtils } from '../src/utils/order_validation_utils';
-
-import { chaiSetup } from './utils/chai_setup';
-import { constants } from './utils/constants';
-import { FillScenarios } from './utils/fill_scenarios';
-import { TokenUtils } from './utils/token_utils';
-import { provider, web3Wrapper } from './utils/web3_wrapper';
-
-chaiSetup.configure();
-const expect = chai.expect;
-const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
-
-describe('OrderValidation', () => {
- let zeroEx: ZeroEx;
- let userAddresses: string[];
- let tokens: Token[];
- let tokenUtils: TokenUtils;
- let exchangeContractAddress: string;
- let zrxTokenAddress: string;
- let fillScenarios: FillScenarios;
- let makerTokenAddress: string;
- let takerTokenAddress: string;
- let coinbase: string;
- let makerAddress: string;
- let takerAddress: string;
- let feeRecipient: string;
- const fillableAmount = new BigNumber(5);
- const fillTakerAmount = new BigNumber(5);
- const config = {
- networkId: constants.TESTRPC_NETWORK_ID,
- };
- before(async () => {
- zeroEx = new ZeroEx(provider, config);
- exchangeContractAddress = zeroEx.exchange.getContractAddress();
- userAddresses = await zeroEx.getAvailableAddressesAsync();
- [coinbase, makerAddress, takerAddress, feeRecipient] = userAddresses;
- tokens = await zeroEx.tokenRegistry.getTokensAsync();
- tokenUtils = new TokenUtils(tokens);
- zrxTokenAddress = tokenUtils.getProtocolTokenOrThrow().address;
- fillScenarios = new FillScenarios(zeroEx, userAddresses, tokens, zrxTokenAddress, exchangeContractAddress);
- const [makerToken, takerToken] = tokenUtils.getDummyTokens();
- makerTokenAddress = makerToken.address;
- takerTokenAddress = takerToken.address;
- });
- beforeEach(async () => {
- await blockchainLifecycle.startAsync();
- });
- afterEach(async () => {
- await blockchainLifecycle.revertAsync();
- });
- describe('validateOrderFillableOrThrowAsync', () => {
- it('should succeed if the order is fillable', async () => {
- const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
- makerTokenAddress,
- takerTokenAddress,
- makerAddress,
- takerAddress,
- fillableAmount,
- );
- await zeroEx.exchange.validateOrderFillableOrThrowAsync(signedOrder);
- });
- it('should succeed if the maker is buying ZRX and has no ZRX balance', async () => {
- const makerFee = new BigNumber(2);
- const takerFee = new BigNumber(2);
- const signedOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync(
- makerTokenAddress,
- zrxTokenAddress,
- makerFee,
- takerFee,
- makerAddress,
- takerAddress,
- fillableAmount,
- feeRecipient,
- );
- const zrxMakerBalance = await zeroEx.token.getBalanceAsync(zrxTokenAddress, makerAddress);
- await zeroEx.token.transferAsync(zrxTokenAddress, makerAddress, takerAddress, zrxMakerBalance);
- await zeroEx.exchange.validateOrderFillableOrThrowAsync(signedOrder);
- });
- it('should succeed if the maker is buying ZRX and has no ZRX balance and there is no specified taker', async () => {
- const makerFee = new BigNumber(2);
- const takerFee = new BigNumber(2);
- const signedOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync(
- makerTokenAddress,
- zrxTokenAddress,
- makerFee,
- takerFee,
- makerAddress,
- constants.NULL_ADDRESS,
- fillableAmount,
- feeRecipient,
- );
- const zrxMakerBalance = await zeroEx.token.getBalanceAsync(zrxTokenAddress, makerAddress);
- await zeroEx.token.transferAsync(zrxTokenAddress, makerAddress, takerAddress, zrxMakerBalance);
- await zeroEx.exchange.validateOrderFillableOrThrowAsync(signedOrder);
- });
- it('should succeed if the order is asymmetric and fillable', async () => {
- const makerFillableAmount = fillableAmount;
- const takerFillableAmount = fillableAmount.minus(4);
- const signedOrder = await fillScenarios.createAsymmetricFillableSignedOrderAsync(
- makerTokenAddress,
- takerTokenAddress,
- makerAddress,
- takerAddress,
- makerFillableAmount,
- takerFillableAmount,
- );
- await zeroEx.exchange.validateOrderFillableOrThrowAsync(signedOrder);
- });
- it('should throw when the order is fully filled or cancelled', async () => {
- const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
- makerTokenAddress,
- takerTokenAddress,
- makerAddress,
- takerAddress,
- fillableAmount,
- );
- await zeroEx.exchange.cancelOrderAsync(signedOrder, fillableAmount);
- return expect(zeroEx.exchange.validateOrderFillableOrThrowAsync(signedOrder)).to.be.rejectedWith(
- ExchangeContractErrs.OrderRemainingFillAmountZero,
- );
- });
- it('should throw when order is expired', async () => {
- const expirationInPast = new BigNumber(1496826058); // 7th Jun 2017
- const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
- makerTokenAddress,
- takerTokenAddress,
- makerAddress,
- takerAddress,
- fillableAmount,
- expirationInPast,
- );
- return expect(zeroEx.exchange.validateOrderFillableOrThrowAsync(signedOrder)).to.be.rejectedWith(
- ExchangeContractErrs.OrderFillExpired,
- );
- });
- });
- describe('validateFillOrderAndThrowIfInvalidAsync', () => {
- it('should throw when the fill amount is zero', async () => {
- const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
- makerTokenAddress,
- takerTokenAddress,
- makerAddress,
- takerAddress,
- fillableAmount,
- );
- const zeroFillAmount = new BigNumber(0);
- return expect(
- zeroEx.exchange.validateFillOrderThrowIfInvalidAsync(signedOrder, zeroFillAmount, takerAddress),
- ).to.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero);
- });
- it('should throw when the signature is invalid', async () => {
- const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
- makerTokenAddress,
- takerTokenAddress,
- makerAddress,
- takerAddress,
- fillableAmount,
- );
- // 27 <--> 28
- signedOrder.ecSignature.v = 28 - signedOrder.ecSignature.v + 27;
- return expect(
- zeroEx.exchange.validateFillOrderThrowIfInvalidAsync(signedOrder, fillableAmount, takerAddress),
- ).to.be.rejectedWith(OrderError.InvalidSignature);
- });
- it('should throw when the order is fully filled or cancelled', async () => {
- const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
- makerTokenAddress,
- takerTokenAddress,
- makerAddress,
- takerAddress,
- fillableAmount,
- );
- await zeroEx.exchange.cancelOrderAsync(signedOrder, fillableAmount);
- return expect(
- zeroEx.exchange.validateFillOrderThrowIfInvalidAsync(signedOrder, fillableAmount, takerAddress),
- ).to.be.rejectedWith(ExchangeContractErrs.OrderRemainingFillAmountZero);
- });
- it('should throw when sender is not a taker', async () => {
- const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
- makerTokenAddress,
- takerTokenAddress,
- makerAddress,
- takerAddress,
- fillableAmount,
- );
- const nonTakerAddress = userAddresses[6];
- return expect(
- zeroEx.exchange.validateFillOrderThrowIfInvalidAsync(signedOrder, fillTakerAmount, nonTakerAddress),
- ).to.be.rejectedWith(ExchangeContractErrs.TransactionSenderIsNotFillOrderTaker);
- });
- it('should throw when order is expired', async () => {
- const expirationInPast = new BigNumber(1496826058); // 7th Jun 2017
- const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
- makerTokenAddress,
- takerTokenAddress,
- makerAddress,
- takerAddress,
- fillableAmount,
- expirationInPast,
- );
- return expect(
- zeroEx.exchange.validateFillOrderThrowIfInvalidAsync(signedOrder, fillTakerAmount, takerAddress),
- ).to.be.rejectedWith(ExchangeContractErrs.OrderFillExpired);
- });
- it('should throw when there a rounding error would have occurred', async () => {
- const makerAmount = new BigNumber(3);
- const takerAmount = new BigNumber(5);
- const signedOrder = await fillScenarios.createAsymmetricFillableSignedOrderAsync(
- makerTokenAddress,
- takerTokenAddress,
- makerAddress,
- takerAddress,
- makerAmount,
- takerAmount,
- );
- const fillTakerAmountThatCausesRoundingError = new BigNumber(3);
- return expect(
- zeroEx.exchange.validateFillOrderThrowIfInvalidAsync(
- signedOrder,
- fillTakerAmountThatCausesRoundingError,
- takerAddress,
- ),
- ).to.be.rejectedWith(ExchangeContractErrs.OrderFillRoundingError);
- });
- });
- describe('#validateFillOrKillOrderAndThrowIfInvalidAsync', () => {
- it('should throw if remaining fillAmount is less then the desired fillAmount', async () => {
- const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
- makerTokenAddress,
- takerTokenAddress,
- makerAddress,
- takerAddress,
- fillableAmount,
- );
- const tooLargeFillAmount = new BigNumber(7);
- const fillAmountDifference = tooLargeFillAmount.minus(fillableAmount);
- await zeroEx.token.transferAsync(takerTokenAddress, coinbase, takerAddress, fillAmountDifference);
- await zeroEx.token.setProxyAllowanceAsync(takerTokenAddress, takerAddress, tooLargeFillAmount);
- await zeroEx.token.transferAsync(makerTokenAddress, coinbase, makerAddress, fillAmountDifference);
- await zeroEx.token.setProxyAllowanceAsync(makerTokenAddress, makerAddress, tooLargeFillAmount);
-
- return expect(
- zeroEx.exchange.validateFillOrKillOrderThrowIfInvalidAsync(
- signedOrder,
- tooLargeFillAmount,
- takerAddress,
- ),
- ).to.be.rejectedWith(ExchangeContractErrs.InsufficientRemainingFillAmount);
- });
- });
- describe('validateCancelOrderAndThrowIfInvalidAsync', () => {
- let signedOrder: SignedOrder;
- const cancelAmount = new BigNumber(3);
- beforeEach(async () => {
- [coinbase, makerAddress, takerAddress] = userAddresses;
- const [makerToken, takerToken] = tokenUtils.getDummyTokens();
- makerTokenAddress = makerToken.address;
- takerTokenAddress = takerToken.address;
- signedOrder = await fillScenarios.createFillableSignedOrderAsync(
- makerTokenAddress,
- takerTokenAddress,
- makerAddress,
- takerAddress,
- fillableAmount,
- );
- });
- it('should throw when cancel amount is zero', async () => {
- const zeroCancelAmount = new BigNumber(0);
- return expect(
- zeroEx.exchange.validateCancelOrderThrowIfInvalidAsync(signedOrder, zeroCancelAmount),
- ).to.be.rejectedWith(ExchangeContractErrs.OrderCancelAmountZero);
- });
- it('should throw when order is expired', async () => {
- const expirationInPast = new BigNumber(1496826058); // 7th Jun 2017
- const expiredSignedOrder = await fillScenarios.createFillableSignedOrderAsync(
- makerTokenAddress,
- takerTokenAddress,
- makerAddress,
- takerAddress,
- fillableAmount,
- expirationInPast,
- );
- return expect(
- zeroEx.exchange.validateCancelOrderThrowIfInvalidAsync(expiredSignedOrder, cancelAmount),
- ).to.be.rejectedWith(ExchangeContractErrs.OrderCancelExpired);
- });
- it('should throw when order is already cancelled or filled', async () => {
- await zeroEx.exchange.cancelOrderAsync(signedOrder, fillableAmount);
- return expect(
- zeroEx.exchange.validateCancelOrderThrowIfInvalidAsync(signedOrder, fillableAmount),
- ).to.be.rejectedWith(ExchangeContractErrs.OrderAlreadyCancelledOrFilled);
- });
- });
- describe('#validateFillOrderBalancesAllowancesThrowIfInvalidAsync', () => {
- let exchangeTransferSimulator: ExchangeTransferSimulator;
- let transferFromAsync: Sinon.SinonSpy;
- const bigNumberMatch = (expected: BigNumber) => {
- return Sinon.match((value: BigNumber) => value.eq(expected));
- };
- beforeEach('create exchangeTransferSimulator', async () => {
- exchangeTransferSimulator = new ExchangeTransferSimulator(zeroEx.token, BlockParamLiteral.Latest);
- transferFromAsync = Sinon.spy();
- exchangeTransferSimulator.transferFromAsync = transferFromAsync as any;
- });
- it('should call exchangeTransferSimulator.transferFrom in a correct order', async () => {
- const makerFee = new BigNumber(2);
- const takerFee = new BigNumber(2);
- const signedOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync(
- makerTokenAddress,
- takerTokenAddress,
- makerFee,
- takerFee,
- makerAddress,
- takerAddress,
- fillableAmount,
- feeRecipient,
- );
- await OrderValidationUtils.validateFillOrderBalancesAllowancesThrowIfInvalidAsync(
- exchangeTransferSimulator,
- signedOrder,
- fillableAmount,
- takerAddress,
- zrxTokenAddress,
- );
- expect(transferFromAsync.callCount).to.be.equal(4);
- expect(
- transferFromAsync
- .getCall(0)
- .calledWith(
- makerTokenAddress,
- makerAddress,
- takerAddress,
- bigNumberMatch(fillableAmount),
- TradeSide.Maker,
- TransferType.Trade,
- ),
- ).to.be.true();
- expect(
- transferFromAsync
- .getCall(1)
- .calledWith(
- takerTokenAddress,
- takerAddress,
- makerAddress,
- bigNumberMatch(fillableAmount),
- TradeSide.Taker,
- TransferType.Trade,
- ),
- ).to.be.true();
- expect(
- transferFromAsync
- .getCall(2)
- .calledWith(
- zrxTokenAddress,
- makerAddress,
- feeRecipient,
- bigNumberMatch(makerFee),
- TradeSide.Maker,
- TransferType.Fee,
- ),
- ).to.be.true();
- expect(
- transferFromAsync
- .getCall(3)
- .calledWith(
- zrxTokenAddress,
- takerAddress,
- feeRecipient,
- bigNumberMatch(takerFee),
- TradeSide.Taker,
- TransferType.Fee,
- ),
- ).to.be.true();
- });
- it('should call exchangeTransferSimulator.transferFrom with correct values for an open order', async () => {
- const makerFee = new BigNumber(2);
- const takerFee = new BigNumber(2);
- const signedOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync(
- makerTokenAddress,
- takerTokenAddress,
- makerFee,
- takerFee,
- makerAddress,
- ZeroEx.NULL_ADDRESS,
- fillableAmount,
- feeRecipient,
- );
- await OrderValidationUtils.validateFillOrderBalancesAllowancesThrowIfInvalidAsync(
- exchangeTransferSimulator,
- signedOrder,
- fillableAmount,
- takerAddress,
- zrxTokenAddress,
- );
- expect(transferFromAsync.callCount).to.be.equal(4);
- expect(
- transferFromAsync
- .getCall(0)
- .calledWith(
- makerTokenAddress,
- makerAddress,
- takerAddress,
- bigNumberMatch(fillableAmount),
- TradeSide.Maker,
- TransferType.Trade,
- ),
- ).to.be.true();
- expect(
- transferFromAsync
- .getCall(1)
- .calledWith(
- takerTokenAddress,
- takerAddress,
- makerAddress,
- bigNumberMatch(fillableAmount),
- TradeSide.Taker,
- TransferType.Trade,
- ),
- ).to.be.true();
- expect(
- transferFromAsync
- .getCall(2)
- .calledWith(
- zrxTokenAddress,
- makerAddress,
- feeRecipient,
- bigNumberMatch(makerFee),
- TradeSide.Maker,
- TransferType.Fee,
- ),
- ).to.be.true();
- expect(
- transferFromAsync
- .getCall(3)
- .calledWith(
- zrxTokenAddress,
- takerAddress,
- feeRecipient,
- bigNumberMatch(takerFee),
- TradeSide.Taker,
- TransferType.Fee,
- ),
- ).to.be.true();
- });
- it('should correctly round the fillMakerTokenAmount', async () => {
- const makerTokenAmount = new BigNumber(3);
- const takerTokenAmount = new BigNumber(1);
- const signedOrder = await fillScenarios.createAsymmetricFillableSignedOrderAsync(
- makerTokenAddress,
- takerTokenAddress,
- makerAddress,
- takerAddress,
- makerTokenAmount,
- takerTokenAmount,
- );
- await OrderValidationUtils.validateFillOrderBalancesAllowancesThrowIfInvalidAsync(
- exchangeTransferSimulator,
- signedOrder,
- takerTokenAmount,
- takerAddress,
- zrxTokenAddress,
- );
- expect(transferFromAsync.callCount).to.be.equal(4);
- const makerFillAmount = transferFromAsync.getCall(0).args[3];
- expect(makerFillAmount).to.be.bignumber.equal(makerTokenAmount);
- });
- it('should correctly round the makerFeeAmount', async () => {
- const makerFee = new BigNumber(2);
- const takerFee = new BigNumber(4);
- const signedOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync(
- makerTokenAddress,
- takerTokenAddress,
- makerFee,
- takerFee,
- makerAddress,
- takerAddress,
- fillableAmount,
- ZeroEx.NULL_ADDRESS,
- );
- const fillTakerTokenAmount = fillableAmount.div(2).round(0);
- await OrderValidationUtils.validateFillOrderBalancesAllowancesThrowIfInvalidAsync(
- exchangeTransferSimulator,
- signedOrder,
- fillTakerTokenAmount,
- takerAddress,
- zrxTokenAddress,
- );
- const makerPartialFee = makerFee.div(2);
- const takerPartialFee = takerFee.div(2);
- expect(transferFromAsync.callCount).to.be.equal(4);
- const partialMakerFee = transferFromAsync.getCall(2).args[3];
- expect(partialMakerFee).to.be.bignumber.equal(makerPartialFee);
- const partialTakerFee = transferFromAsync.getCall(3).args[3];
- expect(partialTakerFee).to.be.bignumber.equal(takerPartialFee);
- });
- });
-}); // tslint:disable-line:max-file-line-count
diff --git a/packages/0x.js/test/remaining_fillable_calculator_test.ts b/packages/0x.js/test/remaining_fillable_calculator_test.ts
deleted file mode 100644
index d97402ef6..000000000
--- a/packages/0x.js/test/remaining_fillable_calculator_test.ts
+++ /dev/null
@@ -1,234 +0,0 @@
-import { ECSignature, SignedOrder } from '@0xproject/types';
-import { BigNumber } from '@0xproject/utils';
-import * as chai from 'chai';
-import 'mocha';
-
-import { ZeroEx } from '../src/0x';
-import { RemainingFillableCalculator } from '../src/order_watcher/remaining_fillable_calculator';
-
-import { chaiSetup } from './utils/chai_setup';
-
-chaiSetup.configure();
-const expect = chai.expect;
-
-describe('RemainingFillableCalculator', () => {
- let calculator: RemainingFillableCalculator;
- let signedOrder: SignedOrder;
- let transferrableMakerTokenAmount: BigNumber;
- let transferrableMakerFeeTokenAmount: BigNumber;
- let remainingMakerTokenAmount: BigNumber;
- let makerAmount: BigNumber;
- let takerAmount: BigNumber;
- let makerFeeAmount: BigNumber;
- let isMakerTokenZRX: boolean;
- const makerToken: string = '0x1';
- const takerToken: string = '0x2';
- const decimals: number = 4;
- const zero: BigNumber = new BigNumber(0);
- const zeroAddress = '0x0';
- const signature: ECSignature = { v: 27, r: '', s: '' };
- beforeEach(async () => {
- [makerAmount, takerAmount, makerFeeAmount] = [
- ZeroEx.toBaseUnitAmount(new BigNumber(50), decimals),
- ZeroEx.toBaseUnitAmount(new BigNumber(5), decimals),
- ZeroEx.toBaseUnitAmount(new BigNumber(1), decimals),
- ];
- [transferrableMakerTokenAmount, transferrableMakerFeeTokenAmount] = [
- ZeroEx.toBaseUnitAmount(new BigNumber(50), decimals),
- ZeroEx.toBaseUnitAmount(new BigNumber(5), decimals),
- ];
- });
- function buildSignedOrder(): SignedOrder {
- return {
- ecSignature: signature,
- exchangeContractAddress: zeroAddress,
- feeRecipient: zeroAddress,
- maker: zeroAddress,
- taker: zeroAddress,
- makerFee: makerFeeAmount,
- takerFee: zero,
- makerTokenAmount: makerAmount,
- takerTokenAmount: takerAmount,
- makerTokenAddress: makerToken,
- takerTokenAddress: takerToken,
- salt: zero,
- expirationUnixTimestampSec: zero,
- };
- }
- describe('Maker token is NOT ZRX', () => {
- before(async () => {
- isMakerTokenZRX = false;
- });
- it('calculates the correct amount when unfilled and funds available', () => {
- signedOrder = buildSignedOrder();
- remainingMakerTokenAmount = signedOrder.makerTokenAmount;
- calculator = new RemainingFillableCalculator(
- signedOrder,
- isMakerTokenZRX,
- transferrableMakerTokenAmount,
- transferrableMakerFeeTokenAmount,
- remainingMakerTokenAmount,
- );
- expect(calculator.computeRemainingMakerFillable()).to.be.bignumber.equal(remainingMakerTokenAmount);
- });
- it('calculates the correct amount when partially filled and funds available', () => {
- signedOrder = buildSignedOrder();
- remainingMakerTokenAmount = ZeroEx.toBaseUnitAmount(new BigNumber(1), decimals);
- calculator = new RemainingFillableCalculator(
- signedOrder,
- isMakerTokenZRX,
- transferrableMakerTokenAmount,
- transferrableMakerFeeTokenAmount,
- remainingMakerTokenAmount,
- );
- expect(calculator.computeRemainingMakerFillable()).to.be.bignumber.equal(remainingMakerTokenAmount);
- });
- it('calculates the amount to be 0 when all fee funds are transferred', () => {
- signedOrder = buildSignedOrder();
- transferrableMakerFeeTokenAmount = zero;
- remainingMakerTokenAmount = signedOrder.makerTokenAmount;
- calculator = new RemainingFillableCalculator(
- signedOrder,
- isMakerTokenZRX,
- transferrableMakerTokenAmount,
- transferrableMakerFeeTokenAmount,
- remainingMakerTokenAmount,
- );
- expect(calculator.computeRemainingMakerFillable()).to.be.bignumber.equal(zero);
- });
- it('calculates the correct amount when balance is less than remaining fillable', () => {
- signedOrder = buildSignedOrder();
- const partiallyFilledAmount = ZeroEx.toBaseUnitAmount(new BigNumber(2), decimals);
- remainingMakerTokenAmount = signedOrder.makerTokenAmount.minus(partiallyFilledAmount);
- transferrableMakerTokenAmount = remainingMakerTokenAmount.minus(partiallyFilledAmount);
- calculator = new RemainingFillableCalculator(
- signedOrder,
- isMakerTokenZRX,
- transferrableMakerTokenAmount,
- transferrableMakerFeeTokenAmount,
- remainingMakerTokenAmount,
- );
- expect(calculator.computeRemainingMakerFillable()).to.be.bignumber.equal(transferrableMakerTokenAmount);
- });
- describe('Order to Fee Ratio is < 1', () => {
- beforeEach(async () => {
- [makerAmount, takerAmount, makerFeeAmount] = [
- ZeroEx.toBaseUnitAmount(new BigNumber(3), decimals),
- ZeroEx.toBaseUnitAmount(new BigNumber(6), decimals),
- ZeroEx.toBaseUnitAmount(new BigNumber(6), decimals),
- ];
- });
- it('calculates the correct amount when funds unavailable', () => {
- signedOrder = buildSignedOrder();
- remainingMakerTokenAmount = signedOrder.makerTokenAmount;
- const transferredAmount = ZeroEx.toBaseUnitAmount(new BigNumber(2), decimals);
- transferrableMakerTokenAmount = remainingMakerTokenAmount.minus(transferredAmount);
- calculator = new RemainingFillableCalculator(
- signedOrder,
- isMakerTokenZRX,
- transferrableMakerTokenAmount,
- transferrableMakerFeeTokenAmount,
- remainingMakerTokenAmount,
- );
- expect(calculator.computeRemainingMakerFillable()).to.be.bignumber.equal(transferrableMakerTokenAmount);
- });
- });
- describe('Ratio is not evenly divisble', () => {
- beforeEach(async () => {
- [makerAmount, takerAmount, makerFeeAmount] = [
- ZeroEx.toBaseUnitAmount(new BigNumber(3), decimals),
- ZeroEx.toBaseUnitAmount(new BigNumber(7), decimals),
- ZeroEx.toBaseUnitAmount(new BigNumber(7), decimals),
- ];
- });
- it('calculates the correct amount when funds unavailable', () => {
- signedOrder = buildSignedOrder();
- remainingMakerTokenAmount = signedOrder.makerTokenAmount;
- const transferredAmount = ZeroEx.toBaseUnitAmount(new BigNumber(2), decimals);
- transferrableMakerTokenAmount = remainingMakerTokenAmount.minus(transferredAmount);
- calculator = new RemainingFillableCalculator(
- signedOrder,
- isMakerTokenZRX,
- transferrableMakerTokenAmount,
- transferrableMakerFeeTokenAmount,
- remainingMakerTokenAmount,
- );
- const calculatedFillableAmount = calculator.computeRemainingMakerFillable();
- expect(calculatedFillableAmount.lessThanOrEqualTo(transferrableMakerTokenAmount)).to.be.true();
- expect(calculatedFillableAmount).to.be.bignumber.greaterThan(new BigNumber(0));
- const orderToFeeRatio = signedOrder.makerTokenAmount.dividedBy(signedOrder.makerFee);
- const calculatedFeeAmount = calculatedFillableAmount.dividedBy(orderToFeeRatio);
- expect(calculatedFeeAmount).to.be.bignumber.lessThan(transferrableMakerFeeTokenAmount);
- });
- });
- });
- describe('Maker Token is ZRX', () => {
- before(async () => {
- isMakerTokenZRX = true;
- });
- it('calculates the correct amount when unfilled and funds available', () => {
- signedOrder = buildSignedOrder();
- transferrableMakerTokenAmount = makerAmount.plus(makerFeeAmount);
- transferrableMakerFeeTokenAmount = transferrableMakerTokenAmount;
- remainingMakerTokenAmount = signedOrder.makerTokenAmount;
- calculator = new RemainingFillableCalculator(
- signedOrder,
- isMakerTokenZRX,
- transferrableMakerTokenAmount,
- transferrableMakerFeeTokenAmount,
- remainingMakerTokenAmount,
- );
- expect(calculator.computeRemainingMakerFillable()).to.be.bignumber.equal(remainingMakerTokenAmount);
- });
- it('calculates the correct amount when partially filled and funds available', () => {
- signedOrder = buildSignedOrder();
- remainingMakerTokenAmount = ZeroEx.toBaseUnitAmount(new BigNumber(1), decimals);
- calculator = new RemainingFillableCalculator(
- signedOrder,
- isMakerTokenZRX,
- transferrableMakerTokenAmount,
- transferrableMakerFeeTokenAmount,
- remainingMakerTokenAmount,
- );
- expect(calculator.computeRemainingMakerFillable()).to.be.bignumber.equal(remainingMakerTokenAmount);
- });
- it('calculates the amount to be 0 when all fee funds are transferred', () => {
- signedOrder = buildSignedOrder();
- transferrableMakerTokenAmount = zero;
- transferrableMakerFeeTokenAmount = zero;
- remainingMakerTokenAmount = signedOrder.makerTokenAmount;
- calculator = new RemainingFillableCalculator(
- signedOrder,
- isMakerTokenZRX,
- transferrableMakerTokenAmount,
- transferrableMakerFeeTokenAmount,
- remainingMakerTokenAmount,
- );
- expect(calculator.computeRemainingMakerFillable()).to.be.bignumber.equal(zero);
- });
- it('calculates the correct amount when balance is less than remaining fillable', () => {
- signedOrder = buildSignedOrder();
- const partiallyFilledAmount = ZeroEx.toBaseUnitAmount(new BigNumber(2), decimals);
- remainingMakerTokenAmount = signedOrder.makerTokenAmount.minus(partiallyFilledAmount);
- transferrableMakerTokenAmount = remainingMakerTokenAmount.minus(partiallyFilledAmount);
- transferrableMakerFeeTokenAmount = transferrableMakerTokenAmount;
-
- const orderToFeeRatio = signedOrder.makerTokenAmount.dividedToIntegerBy(signedOrder.makerFee);
- const expectedFillableAmount = new BigNumber(450980);
- calculator = new RemainingFillableCalculator(
- signedOrder,
- isMakerTokenZRX,
- transferrableMakerTokenAmount,
- transferrableMakerFeeTokenAmount,
- remainingMakerTokenAmount,
- );
- const calculatedFillableAmount = calculator.computeRemainingMakerFillable();
- const numberOfFillsInRatio = calculatedFillableAmount.dividedToIntegerBy(orderToFeeRatio);
- const calculatedFillableAmountPlusFees = calculatedFillableAmount.plus(numberOfFillsInRatio);
- expect(calculatedFillableAmountPlusFees).to.be.bignumber.lessThan(transferrableMakerTokenAmount);
- expect(calculatedFillableAmountPlusFees).to.be.bignumber.lessThan(remainingMakerTokenAmount);
- expect(calculatedFillableAmount).to.be.bignumber.equal(expectedFillableAmount);
- expect(numberOfFillsInRatio.decimalPlaces()).to.be.equal(0);
- });
- });
-});
diff --git a/packages/0x.js/test/subscription_test.ts b/packages/0x.js/test/subscription_test.ts
deleted file mode 100644
index ed4f838c0..000000000
--- a/packages/0x.js/test/subscription_test.ts
+++ /dev/null
@@ -1,82 +0,0 @@
-import { BlockchainLifecycle, devConstants } from '@0xproject/dev-utils';
-import { BigNumber } from '@0xproject/utils';
-import * as _ from 'lodash';
-import 'mocha';
-import * as Sinon from 'sinon';
-
-import { ApprovalContractEventArgs, DecodedLogEvent, Token, TokenEvents, ZeroEx } from '../src';
-import { DoneCallback } from '../src/types';
-
-import { chaiSetup } from './utils/chai_setup';
-import { constants } from './utils/constants';
-import { assertNodeCallbackError } from './utils/report_callback_errors';
-import { provider, web3Wrapper } from './utils/web3_wrapper';
-
-chaiSetup.configure();
-const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
-
-describe('SubscriptionTest', () => {
- let zeroEx: ZeroEx;
- let userAddresses: string[];
- let tokens: Token[];
- let coinbase: string;
- let addressWithoutFunds: string;
- const config = {
- networkId: constants.TESTRPC_NETWORK_ID,
- };
- before(async () => {
- zeroEx = new ZeroEx(provider, config);
- userAddresses = await zeroEx.getAvailableAddressesAsync();
- tokens = await zeroEx.tokenRegistry.getTokensAsync();
- coinbase = userAddresses[0];
- addressWithoutFunds = userAddresses[1];
- });
- beforeEach(async () => {
- await blockchainLifecycle.startAsync();
- });
- afterEach(async () => {
- await blockchainLifecycle.revertAsync();
- });
- describe('#subscribe', () => {
- const indexFilterValues = {};
- let tokenAddress: string;
- const allowanceAmount = new BigNumber(42);
- let stubs: Sinon.SinonStub[] = [];
- before(() => {
- const token = tokens[0];
- tokenAddress = token.address;
- });
- afterEach(() => {
- zeroEx.token.unsubscribeAll();
- _.each(stubs, s => s.restore());
- stubs = [];
- });
- it('Should receive the Error when an error occurs while fetching the block', (done: DoneCallback) => {
- (async () => {
- const errMsg = 'Error fetching block';
- const callback = assertNodeCallbackError(done, errMsg);
- stubs = [Sinon.stub((zeroEx as any)._web3Wrapper, 'getBlockAsync').throws(new Error(errMsg))];
- zeroEx.token.subscribe(tokenAddress, TokenEvents.Approval, indexFilterValues, callback);
- await zeroEx.token.setAllowanceAsync(tokenAddress, coinbase, addressWithoutFunds, allowanceAmount);
- })().catch(done);
- });
- it('Should receive the Error when an error occurs while reconciling the new block', (done: DoneCallback) => {
- (async () => {
- const errMsg = 'Error fetching logs';
- const callback = assertNodeCallbackError(done, errMsg);
- stubs = [Sinon.stub((zeroEx as any)._web3Wrapper, 'getLogsAsync').throws(new Error(errMsg))];
- zeroEx.token.subscribe(tokenAddress, TokenEvents.Approval, indexFilterValues, callback);
- await zeroEx.token.setAllowanceAsync(tokenAddress, coinbase, addressWithoutFunds, allowanceAmount);
- })().catch(done);
- });
- it('Should allow unsubscribeAll to be called successfully after an error', (done: DoneCallback) => {
- (async () => {
- const callback = (err: Error | null, logEvent?: DecodedLogEvent<ApprovalContractEventArgs>) => _.noop;
- zeroEx.token.subscribe(tokenAddress, TokenEvents.Approval, indexFilterValues, callback);
- stubs = [Sinon.stub((zeroEx as any)._web3Wrapper, 'getBlockAsync').throws(new Error('JSON RPC error'))];
- zeroEx.token.unsubscribeAll();
- done();
- })().catch(done);
- });
- });
-});
diff --git a/packages/0x.js/test/token_registry_wrapper_test.ts b/packages/0x.js/test/token_registry_wrapper_test.ts
deleted file mode 100644
index 19caa2ed4..000000000
--- a/packages/0x.js/test/token_registry_wrapper_test.ts
+++ /dev/null
@@ -1,128 +0,0 @@
-import { BlockchainLifecycle, devConstants } from '@0xproject/dev-utils';
-import { schemas, SchemaValidator } from '@0xproject/json-schemas';
-import * as chai from 'chai';
-import * as _ from 'lodash';
-import 'mocha';
-
-import { Token, ZeroEx } from '../src';
-
-import { chaiSetup } from './utils/chai_setup';
-import { constants } from './utils/constants';
-import { provider, web3Wrapper } from './utils/web3_wrapper';
-
-chaiSetup.configure();
-const expect = chai.expect;
-const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
-
-const TOKEN_REGISTRY_SIZE_AFTER_MIGRATION = 7;
-
-describe('TokenRegistryWrapper', () => {
- let zeroEx: ZeroEx;
- let tokens: Token[];
- const tokenAddressBySymbol: { [symbol: string]: string } = {};
- const tokenAddressByName: { [symbol: string]: string } = {};
- const tokenBySymbol: { [symbol: string]: Token } = {};
- const tokenByName: { [symbol: string]: Token } = {};
- const registeredSymbol = 'ZRX';
- const registeredName = '0x Protocol Token';
- const unregisteredSymbol = 'MAL';
- const unregisteredName = 'Malicious Token';
- const config = {
- networkId: constants.TESTRPC_NETWORK_ID,
- };
- before(async () => {
- zeroEx = new ZeroEx(provider, config);
- tokens = await zeroEx.tokenRegistry.getTokensAsync();
- _.map(tokens, token => {
- tokenAddressBySymbol[token.symbol] = token.address;
- tokenAddressByName[token.name] = token.address;
- tokenBySymbol[token.symbol] = token;
- tokenByName[token.name] = token;
- });
- });
- beforeEach(async () => {
- await blockchainLifecycle.startAsync();
- });
- afterEach(async () => {
- await blockchainLifecycle.revertAsync();
- });
- describe('#getTokensAsync', () => {
- it('should return all the tokens added to the tokenRegistry during the migration', async () => {
- expect(tokens).to.have.lengthOf(TOKEN_REGISTRY_SIZE_AFTER_MIGRATION);
-
- const schemaValidator = new SchemaValidator();
- _.each(tokens, token => {
- const validationResult = schemaValidator.validate(token, schemas.tokenSchema);
- expect(validationResult.errors).to.have.lengthOf(0);
- });
- });
- });
- describe('#getTokenAddressesAsync', () => {
- it('should return all the token addresses added to the tokenRegistry during the migration', async () => {
- const tokenAddresses = await zeroEx.tokenRegistry.getTokenAddressesAsync();
- expect(tokenAddresses).to.have.lengthOf(TOKEN_REGISTRY_SIZE_AFTER_MIGRATION);
-
- const schemaValidator = new SchemaValidator();
- _.each(tokenAddresses, tokenAddress => {
- const validationResult = schemaValidator.validate(tokenAddress, schemas.addressSchema);
- expect(validationResult.errors).to.have.lengthOf(0);
- expect(tokenAddress).to.not.be.equal(ZeroEx.NULL_ADDRESS);
- });
- });
- });
- describe('#getTokenAddressBySymbol', () => {
- it('should return correct address for a token in the registry', async () => {
- const tokenAddress = await zeroEx.tokenRegistry.getTokenAddressBySymbolIfExistsAsync(registeredSymbol);
- expect(tokenAddress).to.be.equal(tokenAddressBySymbol[registeredSymbol]);
- });
- it('should return undefined for a token out of registry', async () => {
- const tokenAddress = await zeroEx.tokenRegistry.getTokenAddressBySymbolIfExistsAsync(unregisteredSymbol);
- expect(tokenAddress).to.be.undefined();
- });
- });
- describe('#getTokenAddressByName', () => {
- it('should return correct address for a token in the registry', async () => {
- const tokenAddress = await zeroEx.tokenRegistry.getTokenAddressByNameIfExistsAsync(registeredName);
- expect(tokenAddress).to.be.equal(tokenAddressByName[registeredName]);
- });
- it('should return undefined for a token out of registry', async () => {
- const tokenAddress = await zeroEx.tokenRegistry.getTokenAddressByNameIfExistsAsync(unregisteredName);
- expect(tokenAddress).to.be.undefined();
- });
- });
- describe('#getTokenBySymbol', () => {
- it('should return correct token for a token in the registry', async () => {
- const token = await zeroEx.tokenRegistry.getTokenBySymbolIfExistsAsync(registeredSymbol);
- expect(token).to.be.deep.equal(tokenBySymbol[registeredSymbol]);
- });
- it('should return undefined for a token out of registry', async () => {
- const token = await zeroEx.tokenRegistry.getTokenBySymbolIfExistsAsync(unregisteredSymbol);
- expect(token).to.be.undefined();
- });
- });
- describe('#getTokenByName', () => {
- it('should return correct token for a token in the registry', async () => {
- const token = await zeroEx.tokenRegistry.getTokenByNameIfExistsAsync(registeredName);
- expect(token).to.be.deep.equal(tokenByName[registeredName]);
- });
- it('should return undefined for a token out of registry', async () => {
- const token = await zeroEx.tokenRegistry.getTokenByNameIfExistsAsync(unregisteredName);
- expect(token).to.be.undefined();
- });
- });
- describe('#getTokenIfExistsAsync', () => {
- it('should return the token added to the tokenRegistry during the migration', async () => {
- const aToken = tokens[0];
-
- const token = await zeroEx.tokenRegistry.getTokenIfExistsAsync(aToken.address);
- const schemaValidator = new SchemaValidator();
- const validationResult = schemaValidator.validate(token, schemas.tokenSchema);
- expect(validationResult.errors).to.have.lengthOf(0);
- });
- it('should return return undefined when passed a token address not in the tokenRegistry', async () => {
- const unregisteredTokenAddress = '0x5409ed021d9299bf6814279a6a1411a7e866a631';
- const tokenIfExists = await zeroEx.tokenRegistry.getTokenIfExistsAsync(unregisteredTokenAddress);
- expect(tokenIfExists).to.be.undefined();
- });
- });
-});
diff --git a/packages/0x.js/test/token_transfer_proxy_wrapper_test.ts b/packages/0x.js/test/token_transfer_proxy_wrapper_test.ts
deleted file mode 100644
index 9415d7c08..000000000
--- a/packages/0x.js/test/token_transfer_proxy_wrapper_test.ts
+++ /dev/null
@@ -1,35 +0,0 @@
-import * as chai from 'chai';
-
-import { ZeroEx } from '../src';
-
-import { chaiSetup } from './utils/chai_setup';
-import { constants } from './utils/constants';
-import { provider } from './utils/web3_wrapper';
-
-chaiSetup.configure();
-const expect = chai.expect;
-
-describe('TokenTransferProxyWrapper', () => {
- let zeroEx: ZeroEx;
- const config = {
- networkId: constants.TESTRPC_NETWORK_ID,
- };
- before(async () => {
- zeroEx = new ZeroEx(provider, config);
- });
- describe('#isAuthorizedAsync', () => {
- it('should return false if the address is not authorized', async () => {
- const isAuthorized = await zeroEx.proxy.isAuthorizedAsync(ZeroEx.NULL_ADDRESS);
- expect(isAuthorized).to.be.false();
- });
- });
- describe('#getAuthorizedAddressesAsync', () => {
- it('should return the list of authorized addresses', async () => {
- const authorizedAddresses = await zeroEx.proxy.getAuthorizedAddressesAsync();
- for (const authorizedAddress of authorizedAddresses) {
- const isAuthorized = await zeroEx.proxy.isAuthorizedAsync(authorizedAddress);
- expect(isAuthorized).to.be.true();
- }
- });
- });
-});
diff --git a/packages/0x.js/test/token_wrapper_test.ts b/packages/0x.js/test/token_wrapper_test.ts
deleted file mode 100644
index 04fd943aa..000000000
--- a/packages/0x.js/test/token_wrapper_test.ts
+++ /dev/null
@@ -1,528 +0,0 @@
-import { BlockchainLifecycle, devConstants } from '@0xproject/dev-utils';
-import { EmptyWalletSubprovider } from '@0xproject/subproviders';
-import { Provider } from '@0xproject/types';
-import { BigNumber } from '@0xproject/utils';
-import * as chai from 'chai';
-import 'mocha';
-import Web3ProviderEngine = require('web3-provider-engine');
-
-import {
- ApprovalContractEventArgs,
- BlockParamLiteral,
- BlockRange,
- DecodedLogEvent,
- Token,
- TokenEvents,
- TransferContractEventArgs,
- ZeroEx,
- ZeroExError,
-} from '../src';
-import { DoneCallback } from '../src/types';
-
-import { chaiSetup } from './utils/chai_setup';
-import { constants } from './utils/constants';
-import { reportNodeCallbackErrors } from './utils/report_callback_errors';
-import { TokenUtils } from './utils/token_utils';
-import { provider, web3Wrapper } from './utils/web3_wrapper';
-
-chaiSetup.configure();
-const expect = chai.expect;
-const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
-
-describe('TokenWrapper', () => {
- let zeroEx: ZeroEx;
- let userAddresses: string[];
- let tokens: Token[];
- let tokenUtils: TokenUtils;
- let coinbase: string;
- let addressWithoutFunds: string;
- const config = {
- networkId: constants.TESTRPC_NETWORK_ID,
- };
- before(async () => {
- zeroEx = new ZeroEx(provider, config);
- userAddresses = await zeroEx.getAvailableAddressesAsync();
- tokens = await zeroEx.tokenRegistry.getTokensAsync();
- tokenUtils = new TokenUtils(tokens);
- coinbase = userAddresses[0];
- addressWithoutFunds = userAddresses[1];
- });
- beforeEach(async () => {
- await blockchainLifecycle.startAsync();
- });
- afterEach(async () => {
- await blockchainLifecycle.revertAsync();
- });
- describe('#transferAsync', () => {
- let token: Token;
- let transferAmount: BigNumber;
- before(() => {
- token = tokens[0];
- transferAmount = new BigNumber(42);
- });
- it('should successfully transfer tokens', async () => {
- const fromAddress = coinbase;
- const toAddress = addressWithoutFunds;
- const preBalance = await zeroEx.token.getBalanceAsync(token.address, toAddress);
- expect(preBalance).to.be.bignumber.equal(0);
- await zeroEx.token.transferAsync(token.address, fromAddress, toAddress, transferAmount);
- const postBalance = await zeroEx.token.getBalanceAsync(token.address, toAddress);
- return expect(postBalance).to.be.bignumber.equal(transferAmount);
- });
- it('should fail to transfer tokens if fromAddress has an insufficient balance', async () => {
- const fromAddress = addressWithoutFunds;
- const toAddress = coinbase;
- return expect(
- zeroEx.token.transferAsync(token.address, fromAddress, toAddress, transferAmount),
- ).to.be.rejectedWith(ZeroExError.InsufficientBalanceForTransfer);
- });
- it('should throw a CONTRACT_DOES_NOT_EXIST error for a non-existent token contract', async () => {
- const nonExistentTokenAddress = '0x9dd402f14d67e001d8efbe6583e51bf9706aa065';
- const fromAddress = coinbase;
- const toAddress = coinbase;
- return expect(
- zeroEx.token.transferAsync(nonExistentTokenAddress, fromAddress, toAddress, transferAmount),
- ).to.be.rejectedWith(ZeroExError.TokenContractDoesNotExist);
- });
- });
- describe('#transferFromAsync', () => {
- let token: Token;
- let toAddress: string;
- let senderAddress: string;
- before(async () => {
- token = tokens[0];
- toAddress = addressWithoutFunds;
- senderAddress = userAddresses[2];
- });
- it('should fail to transfer tokens if fromAddress has insufficient allowance set', async () => {
- const fromAddress = coinbase;
- const transferAmount = new BigNumber(42);
-
- const fromAddressBalance = await zeroEx.token.getBalanceAsync(token.address, fromAddress);
- expect(fromAddressBalance).to.be.bignumber.greaterThan(transferAmount);
-
- const fromAddressAllowance = await zeroEx.token.getAllowanceAsync(token.address, fromAddress, toAddress);
- expect(fromAddressAllowance).to.be.bignumber.equal(0);
-
- return expect(
- zeroEx.token.transferFromAsync(token.address, fromAddress, toAddress, senderAddress, transferAmount),
- ).to.be.rejectedWith(ZeroExError.InsufficientAllowanceForTransfer);
- });
- it('[regression] should fail to transfer tokens if set allowance for toAddress instead of senderAddress', async () => {
- const fromAddress = coinbase;
- const transferAmount = new BigNumber(42);
-
- await zeroEx.token.setAllowanceAsync(token.address, fromAddress, toAddress, transferAmount);
-
- return expect(
- zeroEx.token.transferFromAsync(token.address, fromAddress, toAddress, senderAddress, transferAmount),
- ).to.be.rejectedWith(ZeroExError.InsufficientAllowanceForTransfer);
- });
- it('should fail to transfer tokens if fromAddress has insufficient balance', async () => {
- const fromAddress = addressWithoutFunds;
- const transferAmount = new BigNumber(42);
-
- const fromAddressBalance = await zeroEx.token.getBalanceAsync(token.address, fromAddress);
- expect(fromAddressBalance).to.be.bignumber.equal(0);
-
- await zeroEx.token.setAllowanceAsync(token.address, fromAddress, senderAddress, transferAmount);
- const fromAddressAllowance = await zeroEx.token.getAllowanceAsync(
- token.address,
- fromAddress,
- senderAddress,
- );
- expect(fromAddressAllowance).to.be.bignumber.equal(transferAmount);
-
- return expect(
- zeroEx.token.transferFromAsync(token.address, fromAddress, toAddress, senderAddress, transferAmount),
- ).to.be.rejectedWith(ZeroExError.InsufficientBalanceForTransfer);
- });
- it('should successfully transfer tokens', async () => {
- const fromAddress = coinbase;
-
- const preBalance = await zeroEx.token.getBalanceAsync(token.address, toAddress);
- expect(preBalance).to.be.bignumber.equal(0);
-
- const transferAmount = new BigNumber(42);
- await zeroEx.token.setAllowanceAsync(token.address, fromAddress, senderAddress, transferAmount);
-
- await zeroEx.token.transferFromAsync(token.address, fromAddress, toAddress, senderAddress, transferAmount);
- const postBalance = await zeroEx.token.getBalanceAsync(token.address, toAddress);
- return expect(postBalance).to.be.bignumber.equal(transferAmount);
- });
- it('should throw a CONTRACT_DOES_NOT_EXIST error for a non-existent token contract', async () => {
- const fromAddress = coinbase;
- const nonExistentTokenAddress = '0x9dd402f14d67e001d8efbe6583e51bf9706aa065';
- return expect(
- zeroEx.token.transferFromAsync(
- nonExistentTokenAddress,
- fromAddress,
- toAddress,
- senderAddress,
- new BigNumber(42),
- ),
- ).to.be.rejectedWith(ZeroExError.TokenContractDoesNotExist);
- });
- });
- describe('#getBalanceAsync', () => {
- describe('With provider with accounts', () => {
- it('should return the balance for an existing ERC20 token', async () => {
- const token = tokens[0];
- const ownerAddress = coinbase;
- const balance = await zeroEx.token.getBalanceAsync(token.address, ownerAddress);
- const expectedBalance = new BigNumber('1000000000000000000000000000');
- return expect(balance).to.be.bignumber.equal(expectedBalance);
- });
- it('should throw a CONTRACT_DOES_NOT_EXIST error for a non-existent token contract', async () => {
- const nonExistentTokenAddress = '0x9dd402f14d67e001d8efbe6583e51bf9706aa065';
- const ownerAddress = coinbase;
- return expect(zeroEx.token.getBalanceAsync(nonExistentTokenAddress, ownerAddress)).to.be.rejectedWith(
- ZeroExError.TokenContractDoesNotExist,
- );
- });
- it('should return a balance of 0 for a non-existent owner address', async () => {
- const token = tokens[0];
- const nonExistentOwner = '0x198c6ad858f213fb31b6fe809e25040e6b964593';
- const balance = await zeroEx.token.getBalanceAsync(token.address, nonExistentOwner);
- const expectedBalance = new BigNumber(0);
- return expect(balance).to.be.bignumber.equal(expectedBalance);
- });
- });
- describe('With provider without accounts', () => {
- let zeroExWithoutAccounts: ZeroEx;
- before(async () => {
- const hasAddresses = false;
- const emptyWalletProvider = addEmptyWalletSubprovider(provider);
- zeroExWithoutAccounts = new ZeroEx(emptyWalletProvider, config);
- });
- it('should return balance even when called with provider instance without addresses', async () => {
- const token = tokens[0];
- const ownerAddress = coinbase;
- const balance = await zeroExWithoutAccounts.token.getBalanceAsync(token.address, ownerAddress);
- const expectedBalance = new BigNumber('1000000000000000000000000000');
- return expect(balance).to.be.bignumber.equal(expectedBalance);
- });
- });
- });
- describe('#setAllowanceAsync', () => {
- it("should set the spender's allowance", async () => {
- const token = tokens[0];
- const ownerAddress = coinbase;
- const spenderAddress = addressWithoutFunds;
-
- const allowanceBeforeSet = await zeroEx.token.getAllowanceAsync(
- token.address,
- ownerAddress,
- spenderAddress,
- );
- const expectedAllowanceBeforeAllowanceSet = new BigNumber(0);
- expect(allowanceBeforeSet).to.be.bignumber.equal(expectedAllowanceBeforeAllowanceSet);
-
- const amountInBaseUnits = new BigNumber(50);
- await zeroEx.token.setAllowanceAsync(token.address, ownerAddress, spenderAddress, amountInBaseUnits);
-
- const allowanceAfterSet = await zeroEx.token.getAllowanceAsync(token.address, ownerAddress, spenderAddress);
- const expectedAllowanceAfterAllowanceSet = amountInBaseUnits;
- return expect(allowanceAfterSet).to.be.bignumber.equal(expectedAllowanceAfterAllowanceSet);
- });
- });
- describe('#setUnlimitedAllowanceAsync', () => {
- it("should set the unlimited spender's allowance", async () => {
- const token = tokens[0];
- const ownerAddress = coinbase;
- const spenderAddress = addressWithoutFunds;
-
- await zeroEx.token.setUnlimitedAllowanceAsync(token.address, ownerAddress, spenderAddress);
- const allowance = await zeroEx.token.getAllowanceAsync(token.address, ownerAddress, spenderAddress);
- return expect(allowance).to.be.bignumber.equal(zeroEx.token.UNLIMITED_ALLOWANCE_IN_BASE_UNITS);
- });
- it('should reduce the gas cost for transfers including tokens with unlimited allowance support', async () => {
- const transferAmount = new BigNumber(5);
- const zrx = tokenUtils.getProtocolTokenOrThrow();
- const [, userWithNormalAllowance, userWithUnlimitedAllowance] = userAddresses;
- await zeroEx.token.setAllowanceAsync(zrx.address, coinbase, userWithNormalAllowance, transferAmount);
- await zeroEx.token.setUnlimitedAllowanceAsync(zrx.address, coinbase, userWithUnlimitedAllowance);
-
- const initBalanceWithNormalAllowance = await web3Wrapper.getBalanceInWeiAsync(userWithNormalAllowance);
- const initBalanceWithUnlimitedAllowance = await web3Wrapper.getBalanceInWeiAsync(
- userWithUnlimitedAllowance,
- );
-
- await zeroEx.token.transferFromAsync(
- zrx.address,
- coinbase,
- userWithNormalAllowance,
- userWithNormalAllowance,
- transferAmount,
- );
- await zeroEx.token.transferFromAsync(
- zrx.address,
- coinbase,
- userWithUnlimitedAllowance,
- userWithUnlimitedAllowance,
- transferAmount,
- );
-
- const finalBalanceWithNormalAllowance = await web3Wrapper.getBalanceInWeiAsync(userWithNormalAllowance);
- const finalBalanceWithUnlimitedAllowance = await web3Wrapper.getBalanceInWeiAsync(
- userWithUnlimitedAllowance,
- );
-
- const normalGasCost = initBalanceWithNormalAllowance.minus(finalBalanceWithNormalAllowance);
- const unlimitedGasCost = initBalanceWithUnlimitedAllowance.minus(finalBalanceWithUnlimitedAllowance);
-
- // In theory the gas cost with unlimited allowance should be smaller, but with testrpc it's actually bigger.
- // This needs to be investigated in ethereumjs-vm. This test is essentially a repro.
- // TODO: Make this test pass with inverted assertion.
- expect(unlimitedGasCost.toNumber()).to.be.gt(normalGasCost.toNumber());
- });
- });
- describe('#getAllowanceAsync', () => {
- describe('With provider with accounts', () => {
- it('should get the proxy allowance', async () => {
- const token = tokens[0];
- const ownerAddress = coinbase;
- const spenderAddress = addressWithoutFunds;
-
- const amountInBaseUnits = new BigNumber(50);
- await zeroEx.token.setAllowanceAsync(token.address, ownerAddress, spenderAddress, amountInBaseUnits);
-
- const allowance = await zeroEx.token.getAllowanceAsync(token.address, ownerAddress, spenderAddress);
- const expectedAllowance = amountInBaseUnits;
- return expect(allowance).to.be.bignumber.equal(expectedAllowance);
- });
- it('should return 0 if no allowance set yet', async () => {
- const token = tokens[0];
- const ownerAddress = coinbase;
- const spenderAddress = addressWithoutFunds;
- const allowance = await zeroEx.token.getAllowanceAsync(token.address, ownerAddress, spenderAddress);
- const expectedAllowance = new BigNumber(0);
- return expect(allowance).to.be.bignumber.equal(expectedAllowance);
- });
- });
- describe('With provider without accounts', () => {
- let zeroExWithoutAccounts: ZeroEx;
- before(async () => {
- const hasAddresses = false;
- const emptyWalletProvider = addEmptyWalletSubprovider(provider);
- zeroExWithoutAccounts = new ZeroEx(emptyWalletProvider, config);
- });
- it('should get the proxy allowance', async () => {
- const token = tokens[0];
- const ownerAddress = coinbase;
- const spenderAddress = addressWithoutFunds;
-
- const amountInBaseUnits = new BigNumber(50);
- await zeroEx.token.setAllowanceAsync(token.address, ownerAddress, spenderAddress, amountInBaseUnits);
-
- const allowance = await zeroExWithoutAccounts.token.getAllowanceAsync(
- token.address,
- ownerAddress,
- spenderAddress,
- );
- const expectedAllowance = amountInBaseUnits;
- return expect(allowance).to.be.bignumber.equal(expectedAllowance);
- });
- });
- });
- describe('#getProxyAllowanceAsync', () => {
- it('should get the proxy allowance', async () => {
- const token = tokens[0];
- const ownerAddress = coinbase;
-
- const amountInBaseUnits = new BigNumber(50);
- await zeroEx.token.setProxyAllowanceAsync(token.address, ownerAddress, amountInBaseUnits);
-
- const allowance = await zeroEx.token.getProxyAllowanceAsync(token.address, ownerAddress);
- const expectedAllowance = amountInBaseUnits;
- return expect(allowance).to.be.bignumber.equal(expectedAllowance);
- });
- });
- describe('#setProxyAllowanceAsync', () => {
- it('should set the proxy allowance', async () => {
- const token = tokens[0];
- const ownerAddress = coinbase;
-
- const allowanceBeforeSet = await zeroEx.token.getProxyAllowanceAsync(token.address, ownerAddress);
- const expectedAllowanceBeforeAllowanceSet = new BigNumber(0);
- expect(allowanceBeforeSet).to.be.bignumber.equal(expectedAllowanceBeforeAllowanceSet);
-
- const amountInBaseUnits = new BigNumber(50);
- await zeroEx.token.setProxyAllowanceAsync(token.address, ownerAddress, amountInBaseUnits);
-
- const allowanceAfterSet = await zeroEx.token.getProxyAllowanceAsync(token.address, ownerAddress);
- const expectedAllowanceAfterAllowanceSet = amountInBaseUnits;
- return expect(allowanceAfterSet).to.be.bignumber.equal(expectedAllowanceAfterAllowanceSet);
- });
- });
- describe('#setUnlimitedProxyAllowanceAsync', () => {
- it('should set the unlimited proxy allowance', async () => {
- const token = tokens[0];
- const ownerAddress = coinbase;
-
- await zeroEx.token.setUnlimitedProxyAllowanceAsync(token.address, ownerAddress);
- const allowance = await zeroEx.token.getProxyAllowanceAsync(token.address, ownerAddress);
- return expect(allowance).to.be.bignumber.equal(zeroEx.token.UNLIMITED_ALLOWANCE_IN_BASE_UNITS);
- });
- });
- describe('#subscribe', () => {
- const indexFilterValues = {};
- let tokenAddress: string;
- const transferAmount = new BigNumber(42);
- const allowanceAmount = new BigNumber(42);
- before(() => {
- const token = tokens[0];
- tokenAddress = token.address;
- });
- afterEach(() => {
- zeroEx.token.unsubscribeAll();
- });
- // Hack: Mocha does not allow a test to be both async and have a `done` callback
- // Since we need to await the receipt of the event in the `subscribe` callback,
- // we do need both. A hack is to make the top-level a sync fn w/ a done callback and then
- // wrap the rest of the test in an async block
- // Source: https://github.com/mochajs/mocha/issues/2407
- it('Should receive the Transfer event when tokens are transfered', (done: DoneCallback) => {
- (async () => {
- const callback = reportNodeCallbackErrors(done)(
- (logEvent: DecodedLogEvent<TransferContractEventArgs>) => {
- expect(logEvent.isRemoved).to.be.false();
- expect(logEvent.log.logIndex).to.be.equal(0);
- expect(logEvent.log.transactionIndex).to.be.equal(0);
- expect(logEvent.log.blockNumber).to.be.a('number');
- const args = logEvent.log.args;
- expect(args._from).to.be.equal(coinbase);
- expect(args._to).to.be.equal(addressWithoutFunds);
- expect(args._value).to.be.bignumber.equal(transferAmount);
- },
- );
- zeroEx.token.subscribe(tokenAddress, TokenEvents.Transfer, indexFilterValues, callback);
- await zeroEx.token.transferAsync(tokenAddress, coinbase, addressWithoutFunds, transferAmount);
- })().catch(done);
- });
- it('Should receive the Approval event when allowance is being set', (done: DoneCallback) => {
- (async () => {
- const callback = reportNodeCallbackErrors(done)(
- (logEvent: DecodedLogEvent<ApprovalContractEventArgs>) => {
- expect(logEvent).to.not.be.undefined();
- expect(logEvent.isRemoved).to.be.false();
- const args = logEvent.log.args;
- expect(args._owner).to.be.equal(coinbase);
- expect(args._spender).to.be.equal(addressWithoutFunds);
- expect(args._value).to.be.bignumber.equal(allowanceAmount);
- },
- );
- zeroEx.token.subscribe(tokenAddress, TokenEvents.Approval, indexFilterValues, callback);
- await zeroEx.token.setAllowanceAsync(tokenAddress, coinbase, addressWithoutFunds, allowanceAmount);
- })().catch(done);
- });
- it('Outstanding subscriptions are cancelled when zeroEx.setProvider called', (done: DoneCallback) => {
- (async () => {
- const callbackNeverToBeCalled = reportNodeCallbackErrors(done)(
- (logEvent: DecodedLogEvent<ApprovalContractEventArgs>) => {
- done(new Error('Expected this subscription to have been cancelled'));
- },
- );
- zeroEx.token.subscribe(tokenAddress, TokenEvents.Transfer, indexFilterValues, callbackNeverToBeCalled);
- const callbackToBeCalled = reportNodeCallbackErrors(done)();
- zeroEx.setProvider(provider, constants.TESTRPC_NETWORK_ID);
- zeroEx.token.subscribe(tokenAddress, TokenEvents.Transfer, indexFilterValues, callbackToBeCalled);
- await zeroEx.token.transferAsync(tokenAddress, coinbase, addressWithoutFunds, transferAmount);
- })().catch(done);
- });
- it('Should cancel subscription when unsubscribe called', (done: DoneCallback) => {
- (async () => {
- const callbackNeverToBeCalled = reportNodeCallbackErrors(done)(
- (logEvent: DecodedLogEvent<ApprovalContractEventArgs>) => {
- done(new Error('Expected this subscription to have been cancelled'));
- },
- );
- const subscriptionToken = zeroEx.token.subscribe(
- tokenAddress,
- TokenEvents.Transfer,
- indexFilterValues,
- callbackNeverToBeCalled,
- );
- zeroEx.token.unsubscribe(subscriptionToken);
- await zeroEx.token.transferAsync(tokenAddress, coinbase, addressWithoutFunds, transferAmount);
- done();
- })().catch(done);
- });
- });
- describe('#getLogsAsync', () => {
- let tokenAddress: string;
- let tokenTransferProxyAddress: string;
- const blockRange: BlockRange = {
- fromBlock: 0,
- toBlock: BlockParamLiteral.Latest,
- };
- let txHash: string;
- before(() => {
- const token = tokens[0];
- tokenAddress = token.address;
- tokenTransferProxyAddress = zeroEx.proxy.getContractAddress();
- });
- it('should get logs with decoded args emitted by Approval', async () => {
- txHash = await zeroEx.token.setUnlimitedProxyAllowanceAsync(tokenAddress, coinbase);
- await zeroEx.awaitTransactionMinedAsync(txHash);
- const eventName = TokenEvents.Approval;
- const indexFilterValues = {};
- const logs = await zeroEx.token.getLogsAsync<ApprovalContractEventArgs>(
- tokenAddress,
- eventName,
- blockRange,
- indexFilterValues,
- );
- expect(logs).to.have.length(1);
- const args = logs[0].args;
- expect(logs[0].event).to.be.equal(eventName);
- expect(args._owner).to.be.equal(coinbase);
- expect(args._spender).to.be.equal(tokenTransferProxyAddress);
- expect(args._value).to.be.bignumber.equal(zeroEx.token.UNLIMITED_ALLOWANCE_IN_BASE_UNITS);
- });
- it('should only get the logs with the correct event name', async () => {
- txHash = await zeroEx.token.setUnlimitedProxyAllowanceAsync(tokenAddress, coinbase);
- await zeroEx.awaitTransactionMinedAsync(txHash);
- const differentEventName = TokenEvents.Transfer;
- const indexFilterValues = {};
- const logs = await zeroEx.token.getLogsAsync(
- tokenAddress,
- differentEventName,
- blockRange,
- indexFilterValues,
- );
- expect(logs).to.have.length(0);
- });
- it('should only get the logs with the correct indexed fields', async () => {
- txHash = await zeroEx.token.setUnlimitedProxyAllowanceAsync(tokenAddress, coinbase);
- await zeroEx.awaitTransactionMinedAsync(txHash);
- txHash = await zeroEx.token.setUnlimitedProxyAllowanceAsync(tokenAddress, addressWithoutFunds);
- await zeroEx.awaitTransactionMinedAsync(txHash);
- const eventName = TokenEvents.Approval;
- const indexFilterValues = {
- _owner: coinbase,
- };
- const logs = await zeroEx.token.getLogsAsync<ApprovalContractEventArgs>(
- tokenAddress,
- eventName,
- blockRange,
- indexFilterValues,
- );
- expect(logs).to.have.length(1);
- const args = logs[0].args;
- expect(args._owner).to.be.equal(coinbase);
- });
- });
-});
-// tslint:disable:max-file-line-count
-
-function addEmptyWalletSubprovider(p: Provider): Provider {
- const providerEngine = new Web3ProviderEngine();
- providerEngine.addProvider(new EmptyWalletSubprovider());
- const currentSubproviders = (p as any)._providers;
- for (const subprovider of currentSubproviders) {
- providerEngine.addProvider(subprovider);
- }
- providerEngine.start();
- return providerEngine;
-}
diff --git a/packages/0x.js/test/utils/fill_scenarios.ts b/packages/0x.js/test/utils/fill_scenarios.ts
deleted file mode 100644
index 7f28c8af3..000000000
--- a/packages/0x.js/test/utils/fill_scenarios.ts
+++ /dev/null
@@ -1,202 +0,0 @@
-import { orderFactory } from '@0xproject/order-utils';
-import { BigNumber } from '@0xproject/utils';
-import { Web3Wrapper } from '@0xproject/web3-wrapper';
-
-import { SignedOrder, Token, ZeroEx } from '../../src';
-import { artifacts } from '../../src/artifacts';
-import { DummyTokenContract } from '../../src/contract_wrappers/generated/dummy_token';
-
-import { constants } from './constants';
-
-const INITIAL_COINBASE_TOKEN_SUPPLY_IN_UNITS = new BigNumber(100);
-
-export class FillScenarios {
- private _zeroEx: ZeroEx;
- private _userAddresses: string[];
- private _tokens: Token[];
- private _coinbase: string;
- private _zrxTokenAddress: string;
- private _exchangeContractAddress: string;
- constructor(
- zeroEx: ZeroEx,
- userAddresses: string[],
- tokens: Token[],
- zrxTokenAddress: string,
- exchangeContractAddress: string,
- ) {
- this._zeroEx = zeroEx;
- this._userAddresses = userAddresses;
- this._tokens = tokens;
- this._coinbase = userAddresses[0];
- this._zrxTokenAddress = zrxTokenAddress;
- this._exchangeContractAddress = exchangeContractAddress;
- }
- public async initTokenBalancesAsync() {
- const web3Wrapper = (this._zeroEx as any)._web3Wrapper as Web3Wrapper;
- for (const token of this._tokens) {
- if (token.symbol !== 'ZRX' && token.symbol !== 'WETH') {
- const dummyToken = new DummyTokenContract(
- artifacts.DummyTokenArtifact.abi,
- token.address,
- web3Wrapper.getProvider(),
- web3Wrapper.getContractDefaults(),
- );
- const tokenSupply = ZeroEx.toBaseUnitAmount(INITIAL_COINBASE_TOKEN_SUPPLY_IN_UNITS, token.decimals);
- const txHash = await dummyToken.setBalance.sendTransactionAsync(this._coinbase, tokenSupply, {
- from: this._coinbase,
- });
- await this._zeroEx.awaitTransactionMinedAsync(txHash);
- }
- }
- }
- public async createFillableSignedOrderAsync(
- makerTokenAddress: string,
- takerTokenAddress: string,
- makerAddress: string,
- takerAddress: string,
- fillableAmount: BigNumber,
- expirationUnixTimestampSec?: BigNumber,
- ): Promise<SignedOrder> {
- return this.createAsymmetricFillableSignedOrderAsync(
- makerTokenAddress,
- takerTokenAddress,
- makerAddress,
- takerAddress,
- fillableAmount,
- fillableAmount,
- expirationUnixTimestampSec,
- );
- }
- public async createFillableSignedOrderWithFeesAsync(
- makerTokenAddress: string,
- takerTokenAddress: string,
- makerFee: BigNumber,
- takerFee: BigNumber,
- makerAddress: string,
- takerAddress: string,
- fillableAmount: BigNumber,
- feeRecepient: string,
- expirationUnixTimestampSec?: BigNumber,
- ): Promise<SignedOrder> {
- return this._createAsymmetricFillableSignedOrderWithFeesAsync(
- makerTokenAddress,
- takerTokenAddress,
- makerFee,
- takerFee,
- makerAddress,
- takerAddress,
- fillableAmount,
- fillableAmount,
- feeRecepient,
- expirationUnixTimestampSec,
- );
- }
- public async createAsymmetricFillableSignedOrderAsync(
- makerTokenAddress: string,
- takerTokenAddress: string,
- makerAddress: string,
- takerAddress: string,
- makerFillableAmount: BigNumber,
- takerFillableAmount: BigNumber,
- expirationUnixTimestampSec?: BigNumber,
- ): Promise<SignedOrder> {
- const makerFee = new BigNumber(0);
- const takerFee = new BigNumber(0);
- const feeRecepient = constants.NULL_ADDRESS;
- return this._createAsymmetricFillableSignedOrderWithFeesAsync(
- makerTokenAddress,
- takerTokenAddress,
- makerFee,
- takerFee,
- makerAddress,
- takerAddress,
- makerFillableAmount,
- takerFillableAmount,
- feeRecepient,
- expirationUnixTimestampSec,
- );
- }
- public async createPartiallyFilledSignedOrderAsync(
- makerTokenAddress: string,
- takerTokenAddress: string,
- takerAddress: string,
- fillableAmount: BigNumber,
- partialFillAmount: BigNumber,
- ) {
- const [makerAddress] = this._userAddresses;
- const signedOrder = await this.createAsymmetricFillableSignedOrderAsync(
- makerTokenAddress,
- takerTokenAddress,
- makerAddress,
- takerAddress,
- fillableAmount,
- fillableAmount,
- );
- const shouldThrowOnInsufficientBalanceOrAllowance = false;
- await this._zeroEx.exchange.fillOrderAsync(
- signedOrder,
- partialFillAmount,
- shouldThrowOnInsufficientBalanceOrAllowance,
- takerAddress,
- );
- return signedOrder;
- }
- private async _createAsymmetricFillableSignedOrderWithFeesAsync(
- makerTokenAddress: string,
- takerTokenAddress: string,
- makerFee: BigNumber,
- takerFee: BigNumber,
- makerAddress: string,
- takerAddress: string,
- makerFillableAmount: BigNumber,
- takerFillableAmount: BigNumber,
- feeRecepient: string,
- expirationUnixTimestampSec?: BigNumber,
- ): Promise<SignedOrder> {
- await Promise.all([
- this._increaseBalanceAndAllowanceAsync(makerTokenAddress, makerAddress, makerFillableAmount),
- this._increaseBalanceAndAllowanceAsync(takerTokenAddress, takerAddress, takerFillableAmount),
- ]);
- await Promise.all([
- this._increaseBalanceAndAllowanceAsync(this._zrxTokenAddress, makerAddress, makerFee),
- this._increaseBalanceAndAllowanceAsync(this._zrxTokenAddress, takerAddress, takerFee),
- ]);
-
- const signedOrder = await orderFactory.createSignedOrderAsync(
- this._zeroEx.getProvider(),
- makerAddress,
- takerAddress,
- makerFee,
- takerFee,
- makerFillableAmount,
- makerTokenAddress,
- takerFillableAmount,
- takerTokenAddress,
- this._exchangeContractAddress,
- feeRecepient,
- expirationUnixTimestampSec,
- );
- return signedOrder;
- }
- private async _increaseBalanceAndAllowanceAsync(
- tokenAddress: string,
- address: string,
- amount: BigNumber,
- ): Promise<void> {
- if (amount.isZero() || address === ZeroEx.NULL_ADDRESS) {
- return; // noop
- }
- await Promise.all([
- this._increaseBalanceAsync(tokenAddress, address, amount),
- this._increaseAllowanceAsync(tokenAddress, address, amount),
- ]);
- }
- private async _increaseBalanceAsync(tokenAddress: string, address: string, amount: BigNumber): Promise<void> {
- await this._zeroEx.token.transferAsync(tokenAddress, this._coinbase, address, amount);
- }
- private async _increaseAllowanceAsync(tokenAddress: string, address: string, amount: BigNumber): Promise<void> {
- const oldMakerAllowance = await this._zeroEx.token.getProxyAllowanceAsync(tokenAddress, address);
- const newMakerAllowance = oldMakerAllowance.plus(amount);
- await this._zeroEx.token.setProxyAllowanceAsync(tokenAddress, address, newMakerAllowance);
- }
-}
diff --git a/packages/0x.js/test/utils/report_callback_errors.ts b/packages/0x.js/test/utils/report_callback_errors.ts
deleted file mode 100644
index 27c9745c9..000000000
--- a/packages/0x.js/test/utils/report_callback_errors.ts
+++ /dev/null
@@ -1,66 +0,0 @@
-import * as chai from 'chai';
-import * as _ from 'lodash';
-
-import { DoneCallback } from '../../src/types';
-
-const expect = chai.expect;
-
-export const reportNoErrorCallbackErrors = (done: DoneCallback, expectToBeCalledOnce = true) => {
- return <T>(f?: (value: T) => void) => {
- const wrapped = (value: T) => {
- if (_.isUndefined(f)) {
- done();
- return;
- }
- try {
- f(value);
- if (expectToBeCalledOnce) {
- done();
- }
- } catch (err) {
- done(err);
- }
- };
- return wrapped;
- };
-};
-
-export const reportNodeCallbackErrors = (done: DoneCallback, expectToBeCalledOnce = true) => {
- return <T>(f?: (value: T) => void) => {
- const wrapped = (error: Error | null, value: T | undefined) => {
- if (!_.isNull(error)) {
- done(error);
- } else {
- if (_.isUndefined(f)) {
- done();
- return;
- }
- try {
- f(value as T);
- if (expectToBeCalledOnce) {
- done();
- }
- } catch (err) {
- done(err);
- }
- }
- };
- return wrapped;
- };
-};
-
-export const assertNodeCallbackError = (done: DoneCallback, errMsg: string) => {
- const wrapped = <T>(error: Error | null, value: T | undefined) => {
- if (_.isNull(error)) {
- done(new Error('Expected callback to receive an error'));
- } else {
- try {
- expect(error.message).to.be.equal(errMsg);
- done();
- } catch (err) {
- done(err);
- }
- }
- };
- return wrapped;
-};
diff --git a/packages/0x.js/test/utils/token_utils.ts b/packages/0x.js/test/utils/token_utils.ts
index d3fc22ff4..fe4886ba4 100644
--- a/packages/0x.js/test/utils/token_utils.ts
+++ b/packages/0x.js/test/utils/token_utils.ts
@@ -1,6 +1,7 @@
+import { Token } from '@0xproject/types';
import * as _ from 'lodash';
-import { InternalZeroExError, Token } from '../../src/types';
+import { InternalZeroExError } from '../../src/types';
const PROTOCOL_TOKEN_SYMBOL = 'ZRX';
const WETH_TOKEN_SYMBOL = 'WETH';