aboutsummaryrefslogtreecommitdiffstats
path: root/test
diff options
context:
space:
mode:
authorFabio Berger <me@fabioberger.com>2017-11-13 10:12:37 +0800
committerFabio Berger <me@fabioberger.com>2017-11-13 10:12:37 +0800
commite33027c6244b99a1fb181404668bd2a259d923e2 (patch)
tree24438eda01318a80b5cbc7f1939d1640764a9859 /test
parent5d2b6585c66fc17a36bb9841a3b3fb009e23024c (diff)
parentb0be323e899ea7be42b6c695b4fd6d526070b213 (diff)
downloaddexon-sol-tools-e33027c6244b99a1fb181404668bd2a259d923e2.tar
dexon-sol-tools-e33027c6244b99a1fb181404668bd2a259d923e2.tar.gz
dexon-sol-tools-e33027c6244b99a1fb181404668bd2a259d923e2.tar.bz2
dexon-sol-tools-e33027c6244b99a1fb181404668bd2a259d923e2.tar.lz
dexon-sol-tools-e33027c6244b99a1fb181404668bd2a259d923e2.tar.xz
dexon-sol-tools-e33027c6244b99a1fb181404668bd2a259d923e2.tar.zst
dexon-sol-tools-e33027c6244b99a1fb181404668bd2a259d923e2.zip
Merge branch 'development' into feature/receipt-status
* development: (164 commits) Remove old tests Remove unused code Fix tests Remove redundant spaces Don't store empty objects Fix a typo Remove duplicate operations Remove redundant instance variables Fix tests Remove blockStore and default to numConfirmations === 0 Add a comment Store number of confirmations in a blockStore Remove tautology check Pass blockStore to eventWatcher Fix last merge conflicts Clear cache on unsubscribe Clear store cache on events Add more configs for order watcher Make subscribe function async and make blockStore operational Adjust tests to new interface ... # Conflicts: # package.json # src/types.ts # yarn.lock
Diffstat (limited to 'test')
-rw-r--r--test/event_watcher_test.ts127
-rw-r--r--test/exchange_transfer_simulator_test.ts18
-rw-r--r--test/exchange_wrapper_test.ts17
-rw-r--r--test/order_state_watcher_test.ts356
-rw-r--r--test/token_wrapper_test.ts11
-rw-r--r--test/utils/blockchain_lifecycle.ts3
-rw-r--r--test/utils/report_callback_errors.ts14
-rw-r--r--test/utils/rpc.ts6
8 files changed, 530 insertions, 22 deletions
diff --git a/test/event_watcher_test.ts b/test/event_watcher_test.ts
new file mode 100644
index 000000000..b4164fe63
--- /dev/null
+++ b/test/event_watcher_test.ts
@@ -0,0 +1,127 @@
+import 'mocha';
+import * as chai from 'chai';
+import * as _ from 'lodash';
+import * as Sinon from 'sinon';
+import * as Web3 from 'web3';
+import BigNumber from 'bignumber.js';
+import {chaiSetup} from './utils/chai_setup';
+import {web3Factory} from './utils/web3_factory';
+import {Web3Wrapper} from '../src/web3_wrapper';
+import {EventWatcher} from '../src/order_watcher/event_watcher';
+import {
+ ZeroEx,
+ LogEvent,
+ DecodedLogEvent,
+} from '../src';
+import {DoneCallback} from '../src/types';
+
+chaiSetup.configure();
+const expect = chai.expect;
+
+describe('EventWatcher', () => {
+ let web3: Web3;
+ let stubs: Sinon.SinonStub[] = [];
+ let eventWatcher: EventWatcher;
+ let web3Wrapper: Web3Wrapper;
+ const numConfirmations = 0;
+ const logA: Web3.LogEntry = {
+ address: '0x71d271f8b14adef568f8f28f1587ce7271ac4ca5',
+ blockHash: null,
+ blockNumber: null,
+ data: '',
+ logIndex: null,
+ topics: [],
+ transactionHash: '0x004881d38cd4a8f72f1a0d68c8b9b8124504706041ff37019c1d1ed6bfda8e17',
+ transactionIndex: 0,
+ };
+ const logB: Web3.LogEntry = {
+ address: '0x8d12a197cb00d4747a1fe03395095ce2a5cc6819',
+ blockHash: null,
+ blockNumber: null,
+ data: '',
+ logIndex: null,
+ topics: [ '0xf341246adaac6f497bc2a656f546ab9e182111d630394f0c57c710a59a2cb567' ],
+ transactionHash: '0x01ef3c048b18d9b09ea195b4ed94cf8dd5f3d857a1905ff886b152cfb1166f25',
+ transactionIndex: 0,
+ };
+ const logC: Web3.LogEntry = {
+ address: '0x1d271f8b174adef58f1587ce68f8f27271ac4ca5',
+ blockHash: null,
+ blockNumber: null,
+ data: '',
+ logIndex: null,
+ topics: [ '0xf341246adaac6f497bc2a656f546ab9e182111d630394f0c57c710a59a2cb567' ],
+ transactionHash: '0x01ef3c048b18d9b09ea195b4ed94cf8dd5f3d857a1905ff886b152cfb1166f25',
+ transactionIndex: 0,
+ };
+ before(async () => {
+ web3 = web3Factory.create();
+ const pollingIntervalMs = 10;
+ web3Wrapper = new Web3Wrapper(web3.currentProvider);
+ 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: Web3.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 callback = (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: Web3.LogEntry[] = [logA, logB];
+ const changedLogs: Web3.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 callback = (event: LogEvent) => {
+ const expectedLogEvent = expectedLogEvents.shift();
+ expect(event).to.be.deep.equal(expectedLogEvent);
+ if (_.isEmpty(expectedLogEvents)) {
+ done();
+ }
+ };
+ eventWatcher.subscribe(callback);
+ });
+});
diff --git a/test/exchange_transfer_simulator_test.ts b/test/exchange_transfer_simulator_test.ts
index 3373ebf03..99cb7fb4f 100644
--- a/test/exchange_transfer_simulator_test.ts
+++ b/test/exchange_transfer_simulator_test.ts
@@ -59,11 +59,10 @@ describe('ExchangeTransferSimulator', () => {
await exchangeTransferSimulator.transferFromAsync(
exampleTokenAddress, sender, recipient, transferAmount, TradeSide.Taker, TransferType.Trade,
);
- const senderBalance = await (exchangeTransferSimulator as any).getBalanceAsync(exampleTokenAddress, sender);
- const recipientBalance = await (exchangeTransferSimulator as any).getBalanceAsync(
- exampleTokenAddress, recipient);
- const senderProxyAllowance = await (exchangeTransferSimulator as any).getProxyAllowanceAsync(
- exampleTokenAddress, sender);
+ 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);
@@ -76,11 +75,10 @@ describe('ExchangeTransferSimulator', () => {
await exchangeTransferSimulator.transferFromAsync(
exampleTokenAddress, sender, recipient, transferAmount, TradeSide.Taker, TransferType.Trade,
);
- const senderBalance = await (exchangeTransferSimulator as any).getBalanceAsync(exampleTokenAddress, sender);
- const recipientBalance = await (exchangeTransferSimulator as any).getBalanceAsync(
- exampleTokenAddress, recipient);
- const senderProxyAllowance = await (exchangeTransferSimulator as any).getProxyAllowanceAsync(
- exampleTokenAddress, sender);
+ 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/test/exchange_wrapper_test.ts b/test/exchange_wrapper_test.ts
index 654f626c6..26b8c1e0e 100644
--- a/test/exchange_wrapper_test.ts
+++ b/test/exchange_wrapper_test.ts
@@ -11,13 +11,13 @@ import {
SignedOrder,
SubscriptionOpts,
ExchangeEvents,
- ContractEvent,
ExchangeContractErrs,
OrderCancellationRequest,
OrderFillRequest,
LogFillContractEventArgs,
LogCancelContractEventArgs,
LogEvent,
+ DecodedLogEvent,
} from '../src';
import {DoneCallback, BlockParamLiteral} from '../src/types';
import {FillScenarios} from './utils/fill_scenarios';
@@ -70,7 +70,7 @@ describe('ExchangeWrapper', () => {
takerTokenAddress = takerToken.address;
});
describe('#batchFillOrKillAsync', () => {
- it('successfuly batch fillOrKill', async () => {
+ it('successfully batch fillOrKill', async () => {
const fillableAmount = new BigNumber(5);
const partialFillTakerAmount = new BigNumber(2);
const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
@@ -647,7 +647,8 @@ describe('ExchangeWrapper', () => {
// Source: https://github.com/mochajs/mocha/issues/2407
it('Should receive the LogFill event when an order is filled', (done: DoneCallback) => {
(async () => {
- const callback = (err: Error, logEvent: LogEvent<LogFillContractEventArgs>) => {
+
+ const callback = (err: Error, logEvent: DecodedLogEvent<LogFillContractEventArgs>) => {
expect(logEvent.event).to.be.equal(ExchangeEvents.LogFill);
done();
};
@@ -662,7 +663,8 @@ describe('ExchangeWrapper', () => {
});
it('Should receive the LogCancel event when an order is cancelled', (done: DoneCallback) => {
(async () => {
- const callback = (err: Error, logEvent: LogEvent<LogCancelContractEventArgs>) => {
+
+ const callback = (err: Error, logEvent: DecodedLogEvent<LogCancelContractEventArgs>) => {
expect(logEvent.event).to.be.equal(ExchangeEvents.LogCancel);
done();
};
@@ -674,7 +676,8 @@ describe('ExchangeWrapper', () => {
});
it('Outstanding subscriptions are cancelled when zeroEx.setProviderAsync called', (done: DoneCallback) => {
(async () => {
- const callbackNeverToBeCalled = (err: Error, logEvent: LogEvent<LogFillContractEventArgs>) => {
+
+ const callbackNeverToBeCalled = (err: Error, logEvent: DecodedLogEvent<LogFillContractEventArgs>) => {
done(new Error('Expected this subscription to have been cancelled'));
};
await zeroEx.exchange.subscribeAsync(
@@ -684,7 +687,7 @@ describe('ExchangeWrapper', () => {
const newProvider = web3Factory.getRpcProvider();
await zeroEx.setProviderAsync(newProvider);
- const callback = (err: Error, logEvent: LogEvent<LogFillContractEventArgs>) => {
+ const callback = (err: Error, logEvent: DecodedLogEvent<LogFillContractEventArgs>) => {
expect(logEvent.event).to.be.equal(ExchangeEvents.LogFill);
done();
};
@@ -699,7 +702,7 @@ describe('ExchangeWrapper', () => {
});
it('Should cancel subscription when unsubscribe called', (done: DoneCallback) => {
(async () => {
- const callbackNeverToBeCalled = (err: Error, logEvent: LogEvent<LogFillContractEventArgs>) => {
+ const callbackNeverToBeCalled = (err: Error, logEvent: DecodedLogEvent<LogFillContractEventArgs>) => {
done(new Error('Expected this subscription to have been cancelled'));
};
const subscriptionToken = await zeroEx.exchange.subscribeAsync(
diff --git a/test/order_state_watcher_test.ts b/test/order_state_watcher_test.ts
new file mode 100644
index 000000000..c8a4a8064
--- /dev/null
+++ b/test/order_state_watcher_test.ts
@@ -0,0 +1,356 @@
+import 'mocha';
+import * as chai from 'chai';
+import * as _ from 'lodash';
+import * as Web3 from 'web3';
+import BigNumber from 'bignumber.js';
+import { chaiSetup } from './utils/chai_setup';
+import { web3Factory } from './utils/web3_factory';
+import { Web3Wrapper } from '../src/web3_wrapper';
+import { OrderStateWatcher } from '../src/order_watcher/order_state_watcher';
+import {
+ Token,
+ ZeroEx,
+ LogEvent,
+ DecodedLogEvent,
+ ZeroExConfig,
+ OrderState,
+ SignedOrder,
+ ZeroExError,
+ OrderStateValid,
+ OrderStateInvalid,
+ ExchangeContractErrs,
+} from '../src';
+import { TokenUtils } from './utils/token_utils';
+import { FillScenarios } from './utils/fill_scenarios';
+import { DoneCallback } from '../src/types';
+import {BlockchainLifecycle} from './utils/blockchain_lifecycle';
+import {reportCallbackErrors} from './utils/report_callback_errors';
+
+const TIMEOUT_MS = 150;
+
+chaiSetup.configure();
+const expect = chai.expect;
+const blockchainLifecycle = new BlockchainLifecycle();
+
+describe('OrderStateWatcher', () => {
+ let web3: Web3;
+ 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 web3Wrapper: Web3Wrapper;
+ let signedOrder: SignedOrder;
+ const fillableAmount = new BigNumber(5);
+ before(async () => {
+ web3 = web3Factory.create();
+ zeroEx = new ZeroEx(web3.currentProvider);
+ exchangeContractAddress = await zeroEx.exchange.getContractAddressAsync();
+ 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);
+ [makerToken, takerToken] = tokenUtils.getNonProtocolTokens();
+ web3Wrapper = (zeroEx as any)._web3Wrapper;
+ });
+ 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);
+ zeroEx.orderStateWatcher.addOrder(signedOrder);
+ expect((zeroEx.orderStateWatcher as any)._orderByOrderHash).to.include({
+ [orderHash]: signedOrder,
+ });
+ let dependentOrderHashes = (zeroEx.orderStateWatcher as any)._dependentOrderHashes;
+ expect(dependentOrderHashes[signedOrder.maker][signedOrder.makerTokenAddress]).to.have.keys(orderHash);
+ zeroEx.orderStateWatcher.removeOrder(orderHash);
+ expect((zeroEx.orderStateWatcher as any)._orderByOrderHash).to.not.include({
+ [orderHash]: signedOrder,
+ });
+ dependentOrderHashes = (zeroEx.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('')}`;
+ zeroEx.orderStateWatcher.removeOrder(nonExistentOrderHash);
+ });
+ });
+ describe('#subscribe', async () => {
+ afterEach(async () => {
+ zeroEx.orderStateWatcher.unsubscribe();
+ });
+ it('should fail when trying to subscribe twice', async () => {
+ zeroEx.orderStateWatcher.subscribe(_.noop);
+ expect(() => zeroEx.orderStateWatcher.subscribe(_.noop))
+ .to.throw(ZeroExError.SubscriptionAlreadyPresent);
+ });
+ });
+ describe('tests with cleanup', async () => {
+ afterEach(async () => {
+ zeroEx.orderStateWatcher.unsubscribe();
+ const orderHash = ZeroEx.getOrderHashHex(signedOrder);
+ zeroEx.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);
+ zeroEx.orderStateWatcher.addOrder(signedOrder);
+ const callback = reportCallbackErrors(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);
+ done();
+ });
+ zeroEx.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,
+ );
+ const orderHash = ZeroEx.getOrderHashHex(signedOrder);
+ zeroEx.orderStateWatcher.addOrder(signedOrder);
+ const callback = reportCallbackErrors(done)((orderState: OrderState) => {
+ throw new Error('OrderState callback fired for irrelevant order');
+ });
+ zeroEx.orderStateWatcher.subscribe(callback);
+ const notTheMaker = userAddresses[0];
+ const anyRecipient = taker;
+ const transferAmount = new BigNumber(2);
+ const notTheMakerBalance = await zeroEx.token.getBalanceAsync(makerToken.address, notTheMaker);
+ 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);
+ zeroEx.orderStateWatcher.addOrder(signedOrder);
+ const callback = reportCallbackErrors(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);
+ done();
+ });
+ zeroEx.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);
+ zeroEx.orderStateWatcher.addOrder(signedOrder);
+
+ let eventCount = 0;
+ const callback = reportCallbackErrors(done)((orderState: OrderState) => {
+ eventCount++;
+ 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);
+ if (eventCount === 2) {
+ done();
+ }
+ });
+ zeroEx.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 takerBalance = await zeroEx.token.getBalanceAsync(makerToken.address, taker);
+
+ const fillAmountInBaseUnits = new BigNumber(2);
+ const orderHash = ZeroEx.getOrderHashHex(signedOrder);
+ zeroEx.orderStateWatcher.addOrder(signedOrder);
+
+ let eventCount = 0;
+ const callback = reportCallbackErrors(done)((orderState: OrderState) => {
+ eventCount++;
+ 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.makerBalance).to.be.bignumber.equal(remainingMakerBalance);
+ if (eventCount === 2) {
+ done();
+ }
+ });
+ zeroEx.orderStateWatcher.subscribe(callback);
+ const shouldThrowOnInsufficientBalanceOrAllowance = true;
+ await zeroEx.exchange.fillOrderAsync(
+ signedOrder, fillAmountInBaseUnits, shouldThrowOnInsufficientBalanceOrAllowance, taker,
+ );
+ })().catch(done);
+ });
+ describe('remainingFillableMakerTokenAmount', () => {
+ it('should calculate correct remaining fillable', (done: DoneCallback) => {
+ (async () => {
+ const takerFillableAmount = new BigNumber(10);
+ const makerFillableAmount = new BigNumber(20);
+ signedOrder = await fillScenarios.createAsymmetricFillableSignedOrderAsync(
+ makerToken.address, takerToken.address, maker, taker, makerFillableAmount, takerFillableAmount);
+ const makerBalance = await zeroEx.token.getBalanceAsync(makerToken.address, maker);
+ const takerBalance = await zeroEx.token.getBalanceAsync(makerToken.address, taker);
+ const fillAmountInBaseUnits = new BigNumber(2);
+ const orderHash = ZeroEx.getOrderHashHex(signedOrder);
+ zeroEx.orderStateWatcher.addOrder(signedOrder);
+ let eventCount = 0;
+ const callback = reportCallbackErrors(done)((orderState: OrderState) => {
+ eventCount++;
+ 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(
+ new BigNumber(16));
+ if (eventCount === 2) {
+ done();
+ }
+ });
+ zeroEx.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 makerBalance = await zeroEx.token.getBalanceAsync(makerToken.address, maker);
+
+ const changedMakerApprovalAmount = new BigNumber(3);
+ zeroEx.orderStateWatcher.addOrder(signedOrder);
+
+ const callback = reportCallbackErrors(done)((orderState: OrderState) => {
+ const validOrderState = orderState as OrderStateValid;
+ const orderRelevantState = validOrderState.orderRelevantState;
+ expect(orderRelevantState.remainingFillableMakerTokenAmount).to.be.bignumber.equal(
+ changedMakerApprovalAmount);
+ done();
+ });
+ zeroEx.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 = new BigNumber(1);
+ const transferAmount = makerBalance.sub(remainingAmount);
+ zeroEx.orderStateWatcher.addOrder(signedOrder);
+
+ const callback = reportCallbackErrors(done)((orderState: OrderState) => {
+ const validOrderState = orderState as OrderStateValid;
+ const orderRelevantState = validOrderState.orderRelevantState;
+ expect(orderRelevantState.remainingFillableMakerTokenAmount).to.be.bignumber.equal(
+ remainingAmount);
+ done();
+ });
+ zeroEx.orderStateWatcher.subscribe(callback);
+ await zeroEx.token.transferAsync(
+ makerToken.address, maker, ZeroEx.NULL_ADDRESS, transferAmount);
+ })().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);
+ zeroEx.orderStateWatcher.addOrder(signedOrder);
+
+ const callback = reportCallbackErrors(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);
+ done();
+ });
+ zeroEx.orderStateWatcher.subscribe(callback);
+
+ const shouldThrowOnInsufficientBalanceOrAllowance = true;
+ await zeroEx.exchange.cancelOrderAsync(signedOrder, fillableAmount);
+ })().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 makerBalance = await zeroEx.token.getBalanceAsync(makerToken.address, maker);
+ const takerBalance = await zeroEx.token.getBalanceAsync(makerToken.address, taker);
+
+ const cancelAmountInBaseUnits = new BigNumber(2);
+ const orderHash = ZeroEx.getOrderHashHex(signedOrder);
+ zeroEx.orderStateWatcher.addOrder(signedOrder);
+
+ const callback = reportCallbackErrors(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.canceledTakerTokenAmount).to.be.bignumber.equal(cancelAmountInBaseUnits);
+ done();
+ });
+ zeroEx.orderStateWatcher.subscribe(callback);
+ await zeroEx.exchange.cancelOrderAsync(signedOrder, cancelAmountInBaseUnits);
+ })().catch(done);
+ });
+ });
+});
diff --git a/test/token_wrapper_test.ts b/test/token_wrapper_test.ts
index 9b19bf26b..b30762e8c 100644
--- a/test/token_wrapper_test.ts
+++ b/test/token_wrapper_test.ts
@@ -17,6 +17,7 @@ import {
TokenContractEventArgs,
LogWithDecodedArgs,
LogEvent,
+ DecodedLogEvent,
} from '../src';
import {BlockchainLifecycle} from './utils/blockchain_lifecycle';
import {TokenUtils} from './utils/token_utils';
@@ -358,7 +359,7 @@ describe('TokenWrapper', () => {
// Source: https://github.com/mochajs/mocha/issues/2407
it('Should receive the Transfer event when tokens are transfered', (done: DoneCallback) => {
(async () => {
- const callback = (err: Error, logEvent: LogEvent<TransferContractEventArgs>) => {
+ const callback = (err: Error, logEvent: DecodedLogEvent<TransferContractEventArgs>) => {
expect(logEvent).to.not.be.undefined();
const args = logEvent.args;
expect(args._from).to.be.equal(coinbase);
@@ -373,7 +374,7 @@ describe('TokenWrapper', () => {
});
it('Should receive the Approval event when allowance is being set', (done: DoneCallback) => {
(async () => {
- const callback = (err: Error, logEvent: LogEvent<ApprovalContractEventArgs>) => {
+ const callback = (err: Error, logEvent: DecodedLogEvent<ApprovalContractEventArgs>) => {
expect(logEvent).to.not.be.undefined();
const args = logEvent.args;
expect(args._owner).to.be.equal(coinbase);
@@ -388,13 +389,13 @@ describe('TokenWrapper', () => {
});
it('Outstanding subscriptions are cancelled when zeroEx.setProviderAsync called', (done: DoneCallback) => {
(async () => {
- const callbackNeverToBeCalled = (err: Error, logEvent: LogEvent<TransferContractEventArgs>) => {
+ const callbackNeverToBeCalled = (err: Error, logEvent: DecodedLogEvent<ApprovalContractEventArgs>) => {
done(new Error('Expected this subscription to have been cancelled'));
};
zeroEx.token.subscribe(
tokenAddress, TokenEvents.Transfer, indexFilterValues, callbackNeverToBeCalled,
);
- const callbackToBeCalled = (err: Error, logEvent: LogEvent<TransferContractEventArgs>) => {
+ const callbackToBeCalled = (err: Error, logEvent: DecodedLogEvent<ApprovalContractEventArgs>) => {
done();
};
const newProvider = web3Factory.getRpcProvider();
@@ -407,7 +408,7 @@ describe('TokenWrapper', () => {
});
it('Should cancel subscription when unsubscribe called', (done: DoneCallback) => {
(async () => {
- const callbackNeverToBeCalled = (err: Error, logEvent: LogEvent<TokenContractEventArgs>) => {
+ const callbackNeverToBeCalled = (err: Error, logEvent: DecodedLogEvent<ApprovalContractEventArgs>) => {
done(new Error('Expected this subscription to have been cancelled'));
};
const subscriptionToken = zeroEx.token.subscribe(
diff --git a/test/utils/blockchain_lifecycle.ts b/test/utils/blockchain_lifecycle.ts
index 9fdf0e856..9a44ccd6f 100644
--- a/test/utils/blockchain_lifecycle.ts
+++ b/test/utils/blockchain_lifecycle.ts
@@ -20,4 +20,7 @@ export class BlockchainLifecycle {
throw new Error(`Snapshot with id #${snapshotId} failed to revert`);
}
}
+ public async mineABlock(): Promise<void> {
+ await this.rpc.mineBlockAsync();
+ }
}
diff --git a/test/utils/report_callback_errors.ts b/test/utils/report_callback_errors.ts
new file mode 100644
index 000000000..d471b2af2
--- /dev/null
+++ b/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/test/utils/rpc.ts b/test/utils/rpc.ts
index f28a85340..299e72e79 100644
--- a/test/utils/rpc.ts
+++ b/test/utils/rpc.ts
@@ -26,6 +26,12 @@ export class RPC {
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,