aboutsummaryrefslogtreecommitdiffstats
path: root/packages/0x.js/test/utils
diff options
context:
space:
mode:
authorFabio Berger <me@fabioberger.com>2017-11-13 11:17:18 +0800
committerFabio Berger <me@fabioberger.com>2017-11-13 11:17:18 +0800
commitc4ee2d73865a1444c079b9e2836b7630a0adf03e (patch)
treeb9c7794e7022fb189675d914f5fe58dcabd67dec /packages/0x.js/test/utils
parenta74ec0effa818a86233fe64cb0dad2c61bbb4bb6 (diff)
downloaddexon-sol-tools-c4ee2d73865a1444c079b9e2836b7630a0adf03e.tar
dexon-sol-tools-c4ee2d73865a1444c079b9e2836b7630a0adf03e.tar.gz
dexon-sol-tools-c4ee2d73865a1444c079b9e2836b7630a0adf03e.tar.bz2
dexon-sol-tools-c4ee2d73865a1444c079b9e2836b7630a0adf03e.tar.lz
dexon-sol-tools-c4ee2d73865a1444c079b9e2836b7630a0adf03e.tar.xz
dexon-sol-tools-c4ee2d73865a1444c079b9e2836b7630a0adf03e.tar.zst
dexon-sol-tools-c4ee2d73865a1444c079b9e2836b7630a0adf03e.zip
Switch over to Lerna + Yarn Workspaces setup for a mono-repo approach
Diffstat (limited to 'packages/0x.js/test/utils')
-rw-r--r--packages/0x.js/test/utils/blockchain_lifecycle.ts26
-rw-r--r--packages/0x.js/test/utils/chai_setup.ts13
-rw-r--r--packages/0x.js/test/utils/constants.ts8
-rw-r--r--packages/0x.js/test/utils/fill_scenarios.ts114
-rw-r--r--packages/0x.js/test/utils/order_factory.ts42
-rw-r--r--packages/0x.js/test/utils/report_callback_errors.ts14
-rw-r--r--packages/0x.js/test/utils/rpc.ts57
-rw-r--r--packages/0x.js/test/utils/token_utils.ts24
-rw-r--r--packages/0x.js/test/utils/web3_factory.ts31
9 files changed, 329 insertions, 0 deletions
diff --git a/packages/0x.js/test/utils/blockchain_lifecycle.ts b/packages/0x.js/test/utils/blockchain_lifecycle.ts
new file mode 100644
index 000000000..9a44ccd6f
--- /dev/null
+++ b/packages/0x.js/test/utils/blockchain_lifecycle.ts
@@ -0,0 +1,26 @@
+import {RPC} from './rpc';
+
+export class BlockchainLifecycle {
+ private rpc: RPC;
+ private snapshotIdsStack: number[];
+ constructor() {
+ this.rpc = new RPC();
+ this.snapshotIdsStack = [];
+ }
+ // TODO: In order to run these tests on an actual node, we should check if we are running against
+ // TestRPC, if so, use snapshots, otherwise re-deploy contracts before every test
+ public async startAsync(): Promise<void> {
+ const snapshotId = await this.rpc.takeSnapshotAsync();
+ this.snapshotIdsStack.push(snapshotId);
+ }
+ public async revertAsync(): Promise<void> {
+ const snapshotId = this.snapshotIdsStack.pop() as number;
+ const didRevert = await this.rpc.revertSnapshotAsync(snapshotId);
+ if (!didRevert) {
+ throw new Error(`Snapshot with id #${snapshotId} failed to revert`);
+ }
+ }
+ public async mineABlock(): Promise<void> {
+ await this.rpc.mineBlockAsync();
+ }
+}
diff --git a/packages/0x.js/test/utils/chai_setup.ts b/packages/0x.js/test/utils/chai_setup.ts
new file mode 100644
index 000000000..c18988106
--- /dev/null
+++ b/packages/0x.js/test/utils/chai_setup.ts
@@ -0,0 +1,13 @@
+import * as chai from 'chai';
+import * as dirtyChai from 'dirty-chai';
+import ChaiBigNumber = require('chai-bignumber');
+import chaiAsPromised = require('chai-as-promised');
+
+export const chaiSetup = {
+ configure() {
+ chai.config.includeStack = true;
+ chai.use(ChaiBigNumber());
+ chai.use(dirtyChai);
+ chai.use(chaiAsPromised);
+ },
+};
diff --git a/packages/0x.js/test/utils/constants.ts b/packages/0x.js/test/utils/constants.ts
new file mode 100644
index 000000000..c7d3aebca
--- /dev/null
+++ b/packages/0x.js/test/utils/constants.ts
@@ -0,0 +1,8 @@
+export const constants = {
+ NULL_ADDRESS: '0x0000000000000000000000000000000000000000',
+ RPC_HOST: 'localhost',
+ RPC_PORT: 8545,
+ TESTRPC_NETWORK_ID: 50,
+ KOVAN_RPC_URL: 'https://kovan.infura.io',
+ ROPSTEN_RPC_URL: 'https://ropsten.infura.io',
+};
diff --git a/packages/0x.js/test/utils/fill_scenarios.ts b/packages/0x.js/test/utils/fill_scenarios.ts
new file mode 100644
index 000000000..a0632b12c
--- /dev/null
+++ b/packages/0x.js/test/utils/fill_scenarios.ts
@@ -0,0 +1,114 @@
+import BigNumber from 'bignumber.js';
+import {ZeroEx, Token, SignedOrder} from '../../src';
+import {orderFactory} from '../utils/order_factory';
+import {constants} from './constants';
+
+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 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,
+ 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/order_factory.ts b/packages/0x.js/test/utils/order_factory.ts
new file mode 100644
index 000000000..6086e09f7
--- /dev/null
+++ b/packages/0x.js/test/utils/order_factory.ts
@@ -0,0 +1,42 @@
+import * as _ from 'lodash';
+import BigNumber from 'bignumber.js';
+import {ZeroEx, SignedOrder} from '../../src';
+
+export const orderFactory = {
+ async createSignedOrderAsync(
+ zeroEx: ZeroEx,
+ maker: string,
+ taker: string,
+ makerFee: BigNumber,
+ takerFee: BigNumber,
+ makerTokenAmount: BigNumber,
+ makerTokenAddress: string,
+ takerTokenAmount: BigNumber,
+ takerTokenAddress: string,
+ exchangeContractAddress: string,
+ feeRecipient: string,
+ expirationUnixTimestampSec?: BigNumber): Promise<SignedOrder> {
+ const defaultExpirationUnixTimestampSec = new BigNumber(2524604400); // Close to infinite
+ expirationUnixTimestampSec = _.isUndefined(expirationUnixTimestampSec) ?
+ defaultExpirationUnixTimestampSec :
+ expirationUnixTimestampSec;
+ const order = {
+ maker,
+ taker,
+ makerFee,
+ takerFee,
+ makerTokenAmount,
+ takerTokenAmount,
+ makerTokenAddress,
+ takerTokenAddress,
+ salt: ZeroEx.generatePseudoRandomSalt(),
+ exchangeContractAddress,
+ feeRecipient,
+ expirationUnixTimestampSec,
+ };
+ const orderHash = ZeroEx.getOrderHashHex(order);
+ const ecSignature = await zeroEx.signOrderHashAsync(orderHash, maker);
+ const signedOrder: SignedOrder = _.assign(order, {ecSignature});
+ return signedOrder;
+ },
+};
diff --git a/packages/0x.js/test/utils/report_callback_errors.ts b/packages/0x.js/test/utils/report_callback_errors.ts
new file mode 100644
index 000000000..d471b2af2
--- /dev/null
+++ b/packages/0x.js/test/utils/report_callback_errors.ts
@@ -0,0 +1,14 @@
+import { DoneCallback } from '../../src/types';
+
+export const reportCallbackErrors = (done: DoneCallback) => {
+ return (f: (...args: any[]) => void) => {
+ const wrapped = (...args: any[]) => {
+ try {
+ f(...args);
+ } catch (err) {
+ done(err);
+ }
+ };
+ return wrapped;
+ };
+};
diff --git a/packages/0x.js/test/utils/rpc.ts b/packages/0x.js/test/utils/rpc.ts
new file mode 100644
index 000000000..299e72e79
--- /dev/null
+++ b/packages/0x.js/test/utils/rpc.ts
@@ -0,0 +1,57 @@
+import * as ethUtil from 'ethereumjs-util';
+import * as request from 'request-promise-native';
+import {constants} from './constants';
+
+export class RPC {
+ private host: string;
+ private port: number;
+ private id: number;
+ constructor() {
+ this.host = constants.RPC_HOST;
+ this.port = constants.RPC_PORT;
+ this.id = 0;
+ }
+ public async takeSnapshotAsync(): Promise<number> {
+ const method = 'evm_snapshot';
+ const params: any[] = [];
+ const payload = this.toPayload(method, params);
+ const snapshotIdHex = await this.sendAsync(payload);
+ const snapshotId = ethUtil.bufferToInt(ethUtil.toBuffer(snapshotIdHex));
+ return snapshotId;
+ }
+ public async revertSnapshotAsync(snapshotId: number): Promise<boolean> {
+ const method = 'evm_revert';
+ const params = [snapshotId];
+ const payload = this.toPayload(method, params);
+ const didRevert = await this.sendAsync(payload);
+ return didRevert;
+ }
+ public async mineBlockAsync(): Promise<void> {
+ const method = 'evm_mine';
+ const params: any[] = [];
+ const payload = this.toPayload(method, params);
+ await this.sendAsync(payload);
+ }
+ private toPayload(method: string, params: any[] = []): string {
+ const payload = JSON.stringify({
+ id: this.id,
+ method,
+ params,
+ });
+ this.id += 1;
+ return payload;
+ }
+ private async sendAsync(payload: string): Promise<any> {
+ const opts = {
+ method: 'POST',
+ uri: `http://${this.host}:${this.port}`,
+ body: payload,
+ headers: {
+ 'content-type': 'application/json',
+ },
+ };
+ const bodyString = await request(opts);
+ const body = JSON.parse(bodyString);
+ return body.result;
+ }
+}
diff --git a/packages/0x.js/test/utils/token_utils.ts b/packages/0x.js/test/utils/token_utils.ts
new file mode 100644
index 000000000..51cb9411c
--- /dev/null
+++ b/packages/0x.js/test/utils/token_utils.ts
@@ -0,0 +1,24 @@
+import * as _ from 'lodash';
+import {Token, InternalZeroExError} from '../../src/types';
+
+const PROTOCOL_TOKEN_SYMBOL = 'ZRX';
+
+export class TokenUtils {
+ private tokens: Token[];
+ constructor(tokens: Token[]) {
+ this.tokens = tokens;
+ }
+ public getProtocolTokenOrThrow(): Token {
+ const zrxToken = _.find(this.tokens, {symbol: PROTOCOL_TOKEN_SYMBOL});
+ if (_.isUndefined(zrxToken)) {
+ throw new Error(InternalZeroExError.ZrxNotInTokenRegistry);
+ }
+ return zrxToken;
+ }
+ public getNonProtocolTokens(): Token[] {
+ const nonProtocolTokens = _.filter(this.tokens, token => {
+ return token.symbol !== PROTOCOL_TOKEN_SYMBOL;
+ });
+ return nonProtocolTokens;
+ }
+}
diff --git a/packages/0x.js/test/utils/web3_factory.ts b/packages/0x.js/test/utils/web3_factory.ts
new file mode 100644
index 000000000..b20070c74
--- /dev/null
+++ b/packages/0x.js/test/utils/web3_factory.ts
@@ -0,0 +1,31 @@
+// HACK: web3 injects XMLHttpRequest into the global scope and ProviderEngine checks XMLHttpRequest
+// to know whether it is running in a browser or node environment. We need it to be undefined since
+// we are not running in a browser env.
+// Filed issue: https://github.com/ethereum/web3.js/issues/844
+(global as any).XMLHttpRequest = undefined;
+import ProviderEngine = require('web3-provider-engine');
+import RpcSubprovider = require('web3-provider-engine/subproviders/rpc');
+import * as Web3 from 'web3';
+import {constants} from './constants';
+import {EmptyWalletSubProvider} from '../../src/subproviders/empty_wallet_subprovider';
+
+export const web3Factory = {
+ create(hasAddresses: boolean = true): Web3 {
+ const provider = this.getRpcProvider(hasAddresses);
+ const web3 = new Web3();
+ web3.setProvider(provider);
+ return web3;
+ },
+ getRpcProvider(hasAddresses: boolean = true): Web3.Provider {
+ const provider = new ProviderEngine();
+ const rpcUrl = `http://${constants.RPC_HOST}:${constants.RPC_PORT}`;
+ if (!hasAddresses) {
+ provider.addProvider(new EmptyWalletSubProvider());
+ }
+ provider.addProvider(new RpcSubprovider({
+ rpcUrl,
+ }));
+ provider.start();
+ return provider;
+ },
+};