From 209266dbed9d7d038c90c2da8d9b99acab77c80c Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Wed, 9 May 2018 20:36:28 +0200 Subject: Split 0x.js into contract-wrappers, order-watcher but keep 0x.js as a unifying library with the same interface --- .../order-watcher/test/expiration_watcher_test.ts | 200 +++++++++++++++++++++ 1 file changed, 200 insertions(+) create mode 100644 packages/order-watcher/test/expiration_watcher_test.ts (limited to 'packages/order-watcher/test/expiration_watcher_test.ts') diff --git a/packages/order-watcher/test/expiration_watcher_test.ts b/packages/order-watcher/test/expiration_watcher_test.ts new file mode 100644 index 000000000..0a2524d78 --- /dev/null +++ b/packages/order-watcher/test/expiration_watcher_test.ts @@ -0,0 +1,200 @@ +import { ContractWrappers } from '@0xproject/contract-wrappers'; +import { BlockchainLifecycle, callbackErrorReporter, devConstants } from '@0xproject/dev-utils'; +import { FillScenarios } from '@0xproject/fill-scenarios'; +import { getOrderHashHex } from '@0xproject/order-utils'; +import { DoneCallback, Token } from '@0xproject/types'; +import { BigNumber } from '@0xproject/utils'; +import * as chai from 'chai'; +import * as _ from 'lodash'; +import 'mocha'; +import * as Sinon from 'sinon'; + +import { artifacts } from '../src/artifacts'; +import { ExpirationWatcher } from '../src/order_watcher/expiration_watcher'; +import { utils } from '../src/utils/utils'; + +import { chaiSetup } from './utils/chai_setup'; +import { constants } from './utils/constants'; +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 contractWrappers: ContractWrappers; + 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, + }; + contractWrappers = new ContractWrappers(provider, config); + exchangeContractAddress = contractWrappers.exchange.getContractAddress(); + userAddresses = await web3Wrapper.getAvailableAddressesAsync(); + tokens = await contractWrappers.tokenRegistry.getTokensAsync(); + tokenUtils = new TokenUtils(tokens); + zrxTokenAddress = tokenUtils.getProtocolTokenOrThrow().address; + fillScenarios = new FillScenarios(provider, userAddresses, tokens, zrxTokenAddress, exchangeContractAddress); + [coinbase, makerAddress, takerAddress, feeRecipient] = userAddresses; + tokens = await contractWrappers.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 = getOrderHashHex(signedOrder); + expirationWatcher.addOrder(orderHash, signedOrder.expirationUnixTimestampSec.times(1000)); + const callbackAsync = callbackErrorReporter.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 = getOrderHashHex(signedOrder); + expirationWatcher.addOrder(orderHash, signedOrder.expirationUnixTimestampSec.times(1000)); + const callbackAsync = callbackErrorReporter.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 = getOrderHashHex(signedOrder1); + const orderHash2 = 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 = callbackErrorReporter.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 = getOrderHashHex(signedOrder1); + const orderHash2 = 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 = callbackErrorReporter.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); + }); +}); -- cgit v1.2.3